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