Botcraft 26.3
Loading...
Searching...
No Matches
EntityManager.cpp
Go to the documentation of this file.
6
8
9#if PROTOCOL_VERSION > 776 /* > 26.2 */
10#include <stdexcept>
11#endif
12
13namespace Botcraft
14{
15 EntityManager::EntityManager(const std::shared_ptr<NetworkManager>& network_manager) : network_manager(network_manager)
16 {
17 local_player = nullptr;
18 }
19
20 std::shared_ptr<LocalPlayer> EntityManager::GetLocalPlayer()
21 {
22 return local_player;
23 }
24
25 std::shared_ptr<Entity> EntityManager::GetEntity(const int id) const
26 {
27 std::shared_lock<std::shared_mutex> lock(entity_manager_mutex);
28 auto it = entities.find(id);
29 return it == entities.end() ? nullptr : it->second;
30 }
31
32 void EntityManager::AddEntity(const std::shared_ptr<Entity>& entity)
33 {
34 if (entity == nullptr)
35 {
36 return;
37 }
38
39 std::scoped_lock<std::shared_mutex> lock(entity_manager_mutex);
40 entities[entity->GetEntityID()] = entity;
41 }
42
47
48
50 {
51 local_player = std::make_shared<LocalPlayer>();
52 local_player->SetEntityID(packet.GetPlayerId());
53#if PROTOCOL_VERSION < 764 /* < 1.20.2 */
54 local_player->SetGameMode(static_cast<GameType>(packet.GetGameType() & 0x03));
55#else
56 local_player->SetGameMode(static_cast<GameType>(packet.GetCommonPlayerSpawnInfo().GetGameType()));
57#endif
58 std::scoped_lock<std::shared_mutex> lock(entity_manager_mutex);
59 entities[packet.GetPlayerId()] = local_player;
60 }
61
62#if PROTOCOL_VERSION < 755 /* < 1.17 */
63 void EntityManager::Handle(ProtocolCraft::ClientboundMoveEntityPacket& packet)
64 {
65 std::scoped_lock<std::shared_mutex> lock(entity_manager_mutex);
66 auto it = entities.find(packet.GetEntityId());
67 if (it == entities.end())
68 {
69 std::shared_ptr<Entity> entity = std::make_shared<UnknownEntity>();
70 entity->SetEntityID(packet.GetEntityId());
71 entities[packet.GetEntityId()] = entity;
72 }
73 }
74#endif
75
77 {
78 std::shared_ptr<Entity> entity = nullptr;
79
80 {
81 std::shared_lock<std::shared_mutex> lock(entity_manager_mutex);
82 auto it = entities.find(packet.GetEntityId());
83 if (it != entities.end())
84 {
85 entity = it->second;
86 }
87 }
88
89 if (entity != nullptr)
90 {
91 Vector3<double> entity_position = entity->GetPosition();
92#if PROTOCOL_VERSION < 777 /* < 26.3 */
93 entity_position = Vector3<double>(
94 (packet.GetXA() / 128.0f + entity_position.x * 32.0f) / 32.0f,
95 (packet.GetYA() / 128.0f + entity_position.y * 32.0f) / 32.0f,
96 (packet.GetZA() / 128.0f + entity_position.z * 32.0f) / 32.0f
97 );
98#else
99 if (packet.GetSingleDelta().has_value())
100 {
101 const std::array<short, 3>& delta = packet.GetSingleDelta().value();
102 for (int i = 0; i < 3; ++i)
103 {
104 if (delta[i] == 0)
105 {
106 continue;
107 }
108 entity_position[i] = (delta[i] + std::round(entity_position[i]) * 4096.0) / 4096.0;
109 }
110 }
111 else if (packet.GetSteppedDeltas().has_value())
112 {
113 const std::vector<std::pair<int, std::array<short, 3>>>& steps = packet.GetSteppedDeltas().value();
114 for (auto& [tick, delta] : steps)
115 {
116 for (int i = 0; i < 3; ++i)
117 {
118 if (delta[i] == 0)
119 {
120 continue;
121 }
122 entity_position[i] = (delta[i] + std::round(entity_position[i]) * 4096.0) / 4096.0;
123 }
124 }
125 }
126 else
127 {
128 throw std::runtime_error("Invalid ClientboundMoveEntityPacket");
129 }
130#endif
131 entity->SetPosition(entity_position);
132 entity->SetOnGround(packet.GetOnGround());
133 }
134 }
135
137 {
138 std::shared_ptr<Entity> entity = nullptr;
139
140 {
141 std::shared_lock<std::shared_mutex> lock(entity_manager_mutex);
142 auto it = entities.find(packet.GetEntityId());
143 if (it != entities.end())
144 {
145 entity = it->second;
146 }
147 }
148
149 if (entity != nullptr)
150 {
151 Vector3<double> entity_position = entity->GetPosition();
152#if PROTOCOL_VERSION < 777 /* < 26.3 */
153 entity_position = Vector3<double>(
154 (packet.GetXA() / 128.0f + entity_position.x * 32.0f) / 32.0f,
155 (packet.GetYA() / 128.0f + entity_position.y * 32.0f) / 32.0f,
156 (packet.GetZA() / 128.0f + entity_position.z * 32.0f) / 32.0f
157 );
158#else
159 if (packet.GetSingleDelta().has_value())
160 {
161 const std::array<short, 3>& delta = packet.GetSingleDelta().value();
162 for (int i = 0; i < 3; ++i)
163 {
164 if (delta[i] == 0)
165 {
166 continue;
167 }
168 entity_position[i] = (delta[i] + std::round(entity_position[i]) * 4096.0) / 4096.0;
169 }
170 }
171 else if (packet.GetSteppedDeltas().has_value())
172 {
173 const std::vector<std::pair<int, std::array<short, 3>>>& steps = packet.GetSteppedDeltas().value();
174 for (auto& [tick, delta] : steps)
175 {
176 for (int i = 0; i < 3; ++i)
177 {
178 if (delta[i] == 0)
179 {
180 continue;
181 }
182 entity_position[i] = (delta[i] + std::round(entity_position[i]) * 4096.0) / 4096.0;
183 }
184 }
185 }
186 else
187 {
188 throw std::runtime_error("Invalid ClientboundMoveEntityPacketPosRot");
189 }
190#endif
191 entity->SetPosition(entity_position);
192 entity->SetYaw(360.0f * packet.GetYRot() / 256.0f);
193 entity->SetPitch(360.0f * packet.GetXRot() / 256.0f);
194 entity->SetOnGround(packet.GetOnGround());
195 }
196 }
197
199 {
200 std::shared_ptr<Entity> entity = nullptr;
201
202 {
203 std::shared_lock<std::shared_mutex> lock(entity_manager_mutex);
204 auto it = entities.find(packet.GetEntityId());
205 if (it != entities.end())
206 {
207 entity = it->second;
208 }
209 }
210
211 if (entity != nullptr)
212 {
213 entity->SetYaw(360.0f * packet.GetYRot() / 256.0f);
214 entity->SetPitch(360.0f * packet.GetXRot() / 256.0f);
215 entity->SetOnGround(packet.GetOnGround());
216 }
217 }
218
220 {
221#if PROTOCOL_VERSION < 458 /* < 1.14 */
222 std::shared_ptr<Entity> entity = Entity::CreateObjectEntity(static_cast<ObjectEntityType>(packet.GetType()));
223#else
224 std::shared_ptr<Entity> entity = Entity::CreateEntity(static_cast<EntityType>(packet.GetType()));
225#endif
226
227 entity->SetEntityID(packet.GetEntityId());
228 entity->SetX(packet.GetX());
229 entity->SetY(packet.GetY());
230 entity->SetZ(packet.GetZ());
231 entity->SetYaw(360.0f * packet.GetYRot() / 256.0f);
232 entity->SetPitch(360.0f * packet.GetXRot() / 256.0f);
233 entity->SetUUID(packet.GetUuid());
234#if PROTOCOL_VERSION < 773 /* < 1.21.9 */
235 // Packet data is in 1/8000 of block per tick, so convert it back to block/tick
236 entity->SetSpeed(Vector3<double>(packet.GetXa(), packet.GetYa(), packet.GetZa()) / 8000.0);
237#else
238 entity->SetSpeed(Vector3<double>(packet.GetMovement()));
239#endif
240
241 std::scoped_lock<std::shared_mutex> lock(entity_manager_mutex);
242 entities[packet.GetEntityId()] = entity;
243 }
244
246 {
247
248 std::shared_ptr<Entity> entity = local_player;
249
250 if (entity == nullptr)
251 {
252 LOG_WARNING("Trying to apply knockback without a valid player");
253 }
254 else
255 {
256#if PROTOCOL_VERSION < 768 /* < 1.21.2 */
257 entity->SetSpeed(entity->GetSpeed() + Vector3<double>(
258 static_cast<double>(packet.GetKnockbackX()),
259 static_cast<double>(packet.GetKnockbackY()),
260 static_cast<double>(packet.GetKnockbackZ())
261 ));
262#else
263 if (packet.GetPlayerKnockback().has_value())
264 {
265 entity->SetSpeed(entity->GetSpeed() + packet.GetPlayerKnockback().value());
266 }
267#endif
268 }
269 }
270
271#if PROTOCOL_VERSION < 759 /* < 1.19 */
272 void EntityManager::Handle(ProtocolCraft::ClientboundAddMobPacket& packet)
273 {
274 std::shared_ptr<Entity> entity = Entity::CreateEntity(static_cast<EntityType>(packet.GetType()));
275
276 entity->SetEntityID(packet.GetEntityId());
277 entity->SetX(packet.GetX());
278 entity->SetY(packet.GetY());
279 entity->SetZ(packet.GetZ());
280 entity->SetYaw(360.0f * packet.GetYRot() / 256.0f);
281 entity->SetPitch(360.0f * packet.GetXRot() / 256.0f);
282 entity->SetUUID(packet.GetUuid());
283
284 std::scoped_lock<std::shared_mutex> lock(entity_manager_mutex);
285 entities[packet.GetEntityId()] = entity;
286 }
287#endif
288
289#if PROTOCOL_VERSION < 770 /* < 1.21.5 */
290 void EntityManager::Handle(ProtocolCraft::ClientboundAddExperienceOrbPacket& packet)
291 {
292 std::shared_ptr<Entity> entity = Entity::CreateEntity(EntityType::ExperienceOrb);
293
294 entity->SetEntityID(packet.GetEntityId());
295 entity->SetX(packet.GetX());
296 entity->SetY(packet.GetY());
297 entity->SetZ(packet.GetZ());
298 // What do we do with the xp value?
299 std::scoped_lock<std::shared_mutex> lock(entity_manager_mutex);
300 entities[packet.GetEntityId()] = entity;
301 }
302#endif
303
304#if PROTOCOL_VERSION < 721 /* < 1.16 */
305 void EntityManager::Handle(ProtocolCraft::ClientboundAddGlobalEntityPacket& packet)
306 {
307 std::shared_ptr<Entity> entity = Entity::CreateEntity(static_cast<EntityType>(packet.GetType()));
308
309 entity->SetEntityID(packet.GetEntityId());
310 entity->SetX(packet.GetX());
311 entity->SetY(packet.GetY());
312 entity->SetZ(packet.GetZ());
313
314 std::scoped_lock<std::shared_mutex> lock(entity_manager_mutex);
315 entities[packet.GetEntityId()] = entity;
316 }
317#endif
318
319#if PROTOCOL_VERSION < 764 /* < 1.20.2 */
320 void EntityManager::Handle(ProtocolCraft::ClientboundAddPlayerPacket& packet)
321 {
322 std::shared_ptr<Entity> entity = nullptr;
323
324 {
325 std::scoped_lock<std::shared_mutex> lock(entity_manager_mutex);
326 auto it = entities.find(packet.GetEntityId());
327 if (it == entities.end())
328 {
330 entities[packet.GetEntityId()] = entity;
331 }
332 else
333 {
334 entity = it->second;
335 }
336 }
337
338 entity->SetEntityID(packet.GetEntityId());
339 entity->SetPosition(Vector3<double>(
340 packet.GetX(),
341 packet.GetY(),
342 packet.GetZ()
343 ));
344 entity->SetYaw(360.0f * packet.GetYRot() / 256.0f);
345 entity->SetPitch(360.0f * packet.GetXRot() / 256.0f);
346 entity->SetUUID(packet.GetPlayerId());
347 }
348#endif
349
351 {
352 local_player->SetHealth(packet.GetHealth());
353 local_player->SetFood(packet.GetFood());
354 local_player->SetFoodSaturation(packet.GetFoodSaturation());
355 }
356
358 {
359 std::shared_ptr<Entity> entity = nullptr;
360
361 {
362 std::shared_lock<std::shared_mutex> lock(entity_manager_mutex);
363 auto it = entities.find(packet.GetEntityId());
364 if (it != entities.end())
365 {
366 entity = it->second;
367 }
368 }
369
370 if (entity != nullptr)
371 {
372#if PROTOCOL_VERSION < 768 /* < 1.21.2 */
373 entity->SetPosition(Vector3<double>(
374 packet.GetX(),
375 packet.GetY(),
376 packet.GetZ()
377 ));
378 entity->SetYaw(360.0f * packet.GetYRot() / 256.0f);
379 entity->SetPitch(360.0f * packet.GetXRot() / 256.0f);
380#else
381 entity->SetPosition(Vector3<double>(
382 packet.GetRelatives() & (1 << 0) ? entity->GetX() + packet.GetChange().GetPosition()[0] : packet.GetChange().GetPosition()[0],
383 packet.GetRelatives() & (1 << 1) ? entity->GetY() + packet.GetChange().GetPosition()[1] : packet.GetChange().GetPosition()[1],
384 packet.GetRelatives() & (1 << 2) ? entity->GetZ() + packet.GetChange().GetPosition()[2] : packet.GetChange().GetPosition()[2]
385 ));
386 entity->SetYaw(packet.GetRelatives() & (1 << 3) ? entity->GetYaw() + packet.GetChange().GetYRot() : packet.GetChange().GetYRot());
387 entity->SetPitch(packet.GetRelatives() & (1 << 4) ? entity->GetPitch() + packet.GetChange().GetXRot() : packet.GetChange().GetXRot());
388#endif
389 entity->SetOnGround(packet.GetOnGround());
390 }
391 }
392
394 {
395 local_player->SetAbilitiesFlags(packet.GetFlags());
396 local_player->SetFlyingSpeed(packet.GetFlyingSpeed());
397 local_player->SetWalkingSpeed(packet.GetWalkingSpeed());
398 }
399
400#if PROTOCOL_VERSION == 755 /* 1.17 */
401 void EntityManager::Handle(ProtocolCraft::ClientboundRemoveEntityPacket& packet)
402 {
403 std::scoped_lock<std::shared_mutex> lock(entity_manager_mutex);
404 entities.erase(packet.GetEntityId());
405 }
406#else
408 {
409 std::scoped_lock<std::shared_mutex> lock(entity_manager_mutex);
410 for (int i = 0; i < packet.GetEntityIds().size(); ++i)
411 {
412 entities.erase(packet.GetEntityIds()[i]);
413 }
414 }
415#endif
416
418 {
419#if PROTOCOL_VERSION < 764 /* < 1.20.2 */
420 local_player->SetGameMode(static_cast<GameType>(packet.GetPlayerGameType()));
421#else
422 local_player->SetGameMode(static_cast<GameType>(packet.GetCommonPlayerSpawnInfo().GetGameType()));
423#endif
424 }
425
427 {
428 switch (packet.GetType())
429 {
430 case 3: // CHANGE_GAME_MODE
431 local_player->SetGameMode(static_cast<GameType>(packet.GetParam()));
432 break;
433 default:
434 break;
435 }
436 }
437
439 {
440 std::shared_ptr<Entity> entity = nullptr;
441
442 {
443 std::shared_lock<std::shared_mutex> lock(entity_manager_mutex);
444 auto it = entities.find(packet.GetEntityId());
445 if (it != entities.end())
446 {
447 entity = it->second;
448 }
449 }
450
451 if (entity == nullptr)
452 {
453 LOG_WARNING("Trying to load metadata in unexisting entity");
454 }
455 else
456 {
457 entity->LoadMetadataFromRawArray(packet.GetPackedItems());
458 }
459 }
460
462 {
463 std::shared_ptr<Entity> entity = nullptr;
464
465 {
466 std::shared_lock<std::shared_mutex> lock(entity_manager_mutex);
467 auto it = entities.find(packet.GetEntityId());
468 if (it != entities.end())
469 {
470 entity = it->second;
471 }
472 }
473
474 if (entity == nullptr)
475 {
476 LOG_WARNING("Trying to set speed of an unexisting entity");
477 }
478 else
479 {
480#if PROTOCOL_VERSION < 773 /* < 1.21.9 */
481 // Packet data is in 1/8000 of block per tick, so convert it back to block/tick
482 entity->SetSpeed(Vector3<double>(packet.GetXA(), packet.GetYA(), packet.GetZA()) / 8000.0);
483#else
484 entity->SetSpeed(Vector3<double>(packet.GetMovement()));
485#endif
486 }
487 }
488
490 {
491 std::shared_ptr<Entity> entity = nullptr;
492
493 {
494 std::shared_lock<std::shared_mutex> lock(entity_manager_mutex);
495 auto it = entities.find(packet.GetEntityId());
496 if (it != entities.end())
497 {
498 entity = it->second;
499 }
500 }
501
502 if (entity == nullptr)
503 {
504 LOG_WARNING("Trying to set equipment of an unexisting entity");
505 }
506 else
507 {
508#if PROTOCOL_VERSION > 730 /* > 1.15.2 */
509 for (auto& p : packet.GetSlots())
510 {
511 entity->SetEquipment(static_cast<EquipmentSlot>(p.first), p.second);
512 }
513#else
514 entity->SetEquipment(static_cast<EquipmentSlot>(packet.GetSlot().first), packet.GetSlot().second);
515#endif
516 }
517 }
518
520 {
521 std::shared_ptr<Entity> entity = nullptr;
522
523 {
524 std::shared_lock<std::shared_mutex> lock(entity_manager_mutex);
525 auto it = entities.find(packet.GetEntityId());
526 if (it != entities.end())
527 {
528 entity = it->second;
529 }
530 }
531
532 if (entity == nullptr)
533 {
534 LOG_WARNING("Trying to set attributes of an unexisting entity");
535 }
536 else if (!entity->IsLivingEntity())
537 {
538 LOG_WARNING("Trying to set attributes of a non LivingEntity");
539 }
540 else
541 {
542 std::shared_ptr<LivingEntity> living_entity = std::dynamic_pointer_cast<LivingEntity>(entity);
543 for (const auto& a : packet.GetAttributes())
544 {
545#if PROTOCOL_VERSION > 765 /* > 1.20.4 */
546 const EntityAttribute::Type type = static_cast<EntityAttribute::Type>(a.GetKey());
547#elif PROTOCOL_VERSION > 709 /* > 1.15.2 */
548 const EntityAttribute::Type type = EntityAttribute::StringToType(a.GetKey().GetFull());
549#else
550 const EntityAttribute::Type type = EntityAttribute::StringToType(a.GetKey());
551#endif
552 EntityAttribute attribute(type, a.GetValue());
553 for (const auto& m : a.GetModifiers())
554 {
555 attribute.SetModifier(
556#if PROTOCOL_VERSION < 767 /* < 1.21 */
557 m.GetUuid(),
558#else
559 m.GetId().GetFull(),
560#endif
561 EntityAttribute::Modifier{ m.GetAmount(), static_cast<EntityAttribute::Modifier::Operation>(m.GetOperation()) }
562 );
563 }
564 living_entity->AddAttribute(attribute);
565 }
566 }
567 }
568
570 {
571 std::shared_ptr<Entity> entity = nullptr;
572
573 {
574 std::shared_lock<std::shared_mutex> lock(entity_manager_mutex);
575 auto it = entities.find(packet.GetEntityId());
576 if (it != entities.end())
577 {
578 entity = it->second;
579 }
580 }
581
582 if (entity == nullptr)
583 {
584 LOG_WARNING("Trying to set effect of an unexisting entity");
585 }
586 else
587 {
588 entity->AddEffect(EntityEffect {
589 static_cast<EntityEffectType>(packet.GetEffectId()), // type
590 static_cast<unsigned char>(packet.GetEffectAmplifier()), //amplifier
591 std::chrono::steady_clock::now() + std::chrono::milliseconds(50 * packet.GetEffectDurationTicks()) // end
592 });
593 }
594 }
595
597 {
598
599 std::shared_ptr<Entity> entity = nullptr;
600
601 {
602 std::shared_lock<std::shared_mutex> lock(entity_manager_mutex);
603 auto it = entities.find(packet.GetEntityId());
604 if (it != entities.end())
605 {
606 entity = it->second;
607 }
608 }
609
610 if (entity == nullptr)
611 {
612 LOG_WARNING("Trying to remove effect of an unexisting entity");
613 }
614 else
615 {
616 entity->RemoveEffect(static_cast<EntityEffectType>(packet.GetEffect()));
617 }
618 }
619
620#if PROTOCOL_VERSION > 767 /* > 1.21.1 */
622 {
623 std::shared_ptr<Entity> entity = nullptr;
624
625 {
626 std::shared_lock<std::shared_mutex> lock(entity_manager_mutex);
627 auto it = entities.find(packet.GetEntityId());
628 if (it != entities.end())
629 {
630 entity = it->second;
631 }
632 }
633
634 if (entity != nullptr)
635 {
636#if PROTOCOL_VERSION < 777 /* < 26.3 */
637 entity->SetPosition(packet.GetValues().GetPosition());
638 if (entity == local_player)
639 {
640 return;
641 }
642 entity->SetYaw(packet.GetValues().GetYRot());
643 entity->SetPitch(packet.GetValues().GetXRot());
644#else
645 if (packet.GetPosition().GetValue().GetLeft().has_value())
646 {
647 entity->SetPosition(packet.GetPosition().GetValue().GetLeft().value().GetSteps().back().GetPosition());
648 }
649 else
650 {
651 entity->SetPosition(packet.GetPosition().GetValue().GetRight().value().GetEndPosition());
652 }
653 if (entity == local_player)
654 {
655 return;
656 }
657 entity->SetYaw(packet.GetYRot());
658 entity->SetPitch(packet.GetXRot());
659#endif
660 entity->SetOnGround(packet.GetOnGround());
661 }
662 }
663
665 {
666 std::shared_ptr<Entity> entity = nullptr;
667
668 {
669 std::shared_lock<std::shared_mutex> lock(entity_manager_mutex);
670 auto it = entities.find(packet.GetEntityId());
671 if (it != entities.end())
672 {
673 entity = it->second;
674 }
675 }
676
677 if (entity == nullptr || !entity->IsAbstractMinecart())
678 {
679 return;
680 }
681
682 // Don't lerp, directly set the position to the last lerp step
683
684 const ProtocolCraft::MinecartBehaviorMinecartStep& step = packet.GetLerpSteps().back();
685 entity->SetPosition(step.GetPosition());
686 entity->SetYaw(360.0f * step.GetYRot() / 256.0f);
687 entity->SetPitch(360.0f * step.GetXRot() / 256.0f);
688 }
689#endif
690}
#define LOG_WARNING(osstream)
Definition Logger.hpp:44
void SetModifier(const ModifierKey &key, const Modifier &modifier)
virtual void Handle(ProtocolCraft::ClientboundLoginPacket &packet) override
std::shared_ptr< LocalPlayer > GetLocalPlayer()
std::shared_ptr< LocalPlayer > local_player
std::shared_mutex entity_manager_mutex
Utilities::ScopeLockedWrapper< const std::unordered_map< int, std::shared_ptr< Entity > >, std::shared_mutex, std::shared_lock > GetEntities() const
Get a read-only locked version of all the loaded entities (including local player)
std::unordered_map< int, std::shared_ptr< Entity > > entities
void AddEntity(const std::shared_ptr< Entity > &entity)
EntityManager(const std::shared_ptr< NetworkManager > &network_manager)
std::shared_ptr< Entity > GetEntity(const int id) const
static std::shared_ptr< Entity > CreateEntity(const EntityType type)
Definition Entity.cpp:1580
Mutex protected reference, will be locked until destroyed.
EquipmentSlot
Definition Enums.hpp:285
EntityEffectType
Definition Enums.hpp:330