the game where you go into mines and start crafting! but for consoles (forked directly from smartcmd's github)
1#include "stdafx.h"
2#include "TrackedEntity.h"
3#include "ServerPlayer.h"
4#include "PlayerConnection.h"
5#include "..\Minecraft.World\Mth.h"
6#include "..\Minecraft.World\net.minecraft.world.entity.h"
7#include "..\Minecraft.World\net.minecraft.world.entity.item.h"
8#include "..\Minecraft.World\net.minecraft.world.entity.monster.h"
9#include "..\Minecraft.World\net.minecraft.world.entity.player.h"
10#include "..\Minecraft.World\net.minecraft.world.entity.animal.h"
11#include "..\Minecraft.World\net.minecraft.world.entity.global.h"
12#include "..\Minecraft.World\net.minecraft.world.entity.projectile.h"
13#include "..\Minecraft.World\net.minecraft.network.packet.h"
14#include "..\Minecraft.World\net.minecraft.world.item.h"
15#include "..\Minecraft.World\net.minecraft.world.level.saveddata.h"
16#include "..\Minecraft.World\net.minecraft.world.entity.ai.attributes.h"
17#include "MinecraftServer.h"
18#include "ServerLevel.h"
19#include "PlayerList.h"
20#include "EntityTracker.h"
21#include "PlayerChunkMap.h"
22#include <qnet.h>
23
24TrackedEntity::TrackedEntity(shared_ptr<Entity> e, int range, int updateInterval, bool trackDelta)
25{
26 // 4J added initialisers
27 xap = yap = zap = 0;
28 tickCount = 0;
29 xpu = ypu = zpu = 0;
30 updatedPlayerVisibility = false;
31 teleportDelay = 0;
32 moved = false;
33 wasRiding = false;
34
35 this->e = e;
36 this->range = range;
37 this->updateInterval = updateInterval;
38 this->trackDelta = trackDelta;
39
40 xp = Mth::floor(e->x * 32);
41 yp = Mth::floor(e->y * 32);
42 zp = Mth::floor(e->z * 32);
43
44 yRotp = Mth::floor(e->yRot * 256 / 360);
45 xRotp = Mth::floor(e->xRot * 256 / 360);
46 yHeadRotp = Mth::floor(e->getYHeadRot() * 256 / 360);
47}
48
49int c0a = 0, c0b = 0, c1a = 0, c1b = 0, c1c = 0, c2a = 0, c2b = 0;
50
51void TrackedEntity::tick(EntityTracker *tracker, vector<shared_ptr<Player> > *players)
52{
53 moved = false;
54 if (!updatedPlayerVisibility || e->distanceToSqr(xpu, ypu, zpu) > 4 * 4)
55 {
56 xpu = e->x;
57 ypu = e->y;
58 zpu = e->z;
59 updatedPlayerVisibility = true;
60 moved = true;
61 updatePlayers(tracker, players);
62 }
63
64 if (lastRidingEntity != e->riding || (e->riding != NULL && tickCount % (SharedConstants::TICKS_PER_SECOND * 3) == 0))
65 {
66 lastRidingEntity = e->riding;
67 broadcast(shared_ptr<SetEntityLinkPacket>(new SetEntityLinkPacket(SetEntityLinkPacket::RIDING, e, e->riding)));
68 }
69
70 // Moving forward special case for item frames
71 if (e->GetType()== eTYPE_ITEM_FRAME && tickCount % 10 == 0)
72 {
73 shared_ptr<ItemFrame> frame = dynamic_pointer_cast<ItemFrame> (e);
74 shared_ptr<ItemInstance> item = frame->getItem();
75
76 if (item != NULL && item->getItem()->id == Item::map_Id && !e->removed)
77 {
78 shared_ptr<MapItemSavedData> data = Item::map->getSavedData(item, e->level);
79 for (AUTO_VAR(it,players->begin() ); it != players->end(); ++it)
80 {
81 shared_ptr<ServerPlayer> player = dynamic_pointer_cast<ServerPlayer>(*it);
82 data->tickCarriedBy(player, item);
83
84 if (!player->removed && player->connection && player->connection->countDelayedPackets() <= 5)
85 {
86 shared_ptr<Packet> packet = Item::map->getUpdatePacket(item, e->level, player);
87 if (packet != NULL) player->connection->send(packet);
88 }
89 }
90 }
91
92 shared_ptr<SynchedEntityData> entityData = e->getEntityData();
93 if (entityData->isDirty())
94 {
95 broadcastAndSend( shared_ptr<SetEntityDataPacket>( new SetEntityDataPacket(e->entityId, entityData, false) ) );
96 }
97 }
98 else if (tickCount % updateInterval == 0 || e->hasImpulse || e->getEntityData()->isDirty())
99 {
100 // 4J: Moved this as it's shared
101 int yRotn = Mth::floor(e->yRot * 256 / 360);
102 int xRotn = Mth::floor(e->xRot * 256 / 360);
103
104 // 4J: Changed rotation to be generally sent as a delta as well as position
105 int yRota = yRotn - yRotp;
106 int xRota = xRotn - xRotp;
107
108 if(e->riding == NULL)
109 {
110 teleportDelay++;
111
112 int xn = Mth::floor(e->x * 32.0);
113 int yn = Mth::floor(e->y * 32.0);
114 int zn = Mth::floor(e->z * 32.0);
115
116 int xa = xn - xp;
117 int ya = yn - yp;
118 int za = zn - zp;
119
120 shared_ptr<Packet> packet = nullptr;
121
122 // 4J - this pos flag used to be set based on abs(xn) etc. but that just seems wrong
123 bool pos = abs(xa) >= TOLERANCE_LEVEL || abs(ya) >= TOLERANCE_LEVEL || abs(za) >= TOLERANCE_LEVEL || (tickCount % (SharedConstants::TICKS_PER_SECOND * 3) == 0);
124
125 // Keep rotation deltas in +/- 180 degree range
126 while( yRota > 127 ) yRota -= 256;
127 while( yRota < -128 ) yRota += 256;
128 while( xRota > 127 ) xRota -= 256;
129 while( xRota < -128 ) xRota += 256;
130
131 bool rot = abs(yRota) >= TOLERANCE_LEVEL || abs(xRota) >= TOLERANCE_LEVEL;
132
133 // 4J: Modified the following check. It was originally added by Mojang to address
134 // certain unspecified issues with entity position. Turns out the issue effects a
135 // variety of different entities so we've left it in and just added the new exceptions
136 // (so far just players)
137
138 // 4J: Original comment follows
139 // TODO: Figure out how to fix this properly
140 // skip first tick since position is sent in addEntity packet
141 // FallingTile depends on this because it removes its source block in the first tick()
142
143 if (tickCount > 0 || e->instanceof(eTYPE_ARROW) || e->instanceof(eTYPE_PLAYER)) // 4J: Modifed, see above
144 {
145 if (xa < -128 || xa >= 128 || ya < -128 || ya >= 128 || za < -128 || za >= 128 || wasRiding
146 // 4J Stu - I fixed the initialisation of teleportDelay in the ctor, but we managed this far without out
147 // and would prefer not to have all the extra traffix so ignore it
148 // 4J Stu - Fix for #9579 - GAMEPLAY: Boats with a player in them slowly sink under the water over time, and with no player in them they float into the sky.
149 || (e->GetType() == eTYPE_BOAT && teleportDelay > 20 * 20)
150 )
151 {
152 teleportDelay = 0;
153 packet = shared_ptr<TeleportEntityPacket>( new TeleportEntityPacket(e->entityId, xn, yn, zn, (byte) yRotn, (byte) xRotn) );
154 // printf("%d: New teleport rot %d\n",e->entityId,yRotn);
155 yRotp = yRotn;
156 xRotp = xRotn;
157 }
158 else
159 {
160 if (pos && rot)
161 {
162 // 4J If the movement is small enough, and there's no xrot, then use the new smaller packets
163 if( ( xa >= -16 ) && ( xa <= 15 ) &&
164 ( za >= -16 ) && ( za <= 15 ) &&
165 ( ya >= -32 ) && ( ya <= 31 ) &&
166 ( xRota == 0 ))
167 {
168 // Clamp rotations that are too big
169 if( yRota < -16 )
170 {
171 yRota = -16;
172 yRotn = yRotp + yRota;
173 }
174 else if( yRota > 15 )
175 {
176 yRota = 15;
177 yRotn = yRotp + yRota;
178 }
179 // 5 bits each for x & z, and 6 for y
180 packet = shared_ptr<MoveEntityPacketSmall>( new MoveEntityPacketSmall::PosRot(e->entityId, (char) xa, (char) ya, (char) za, (char) yRota, 0 ) );
181 c0a++;
182 }
183 else
184 {
185 packet = shared_ptr<MoveEntityPacket>( new MoveEntityPacket::PosRot(e->entityId, (char) xa, (char) ya, (char) za, (char) yRota, (char) xRota) );
186 // printf("%d: New posrot %d + %d = %d\n",e->entityId,yRotp,yRota,yRotn);
187 c0b++;
188 }
189 }
190 else if (pos)
191 {
192 // 4J If the movement is small enough, then use the new smaller packets
193 if( ( xa >= -8 ) && ( xa <= 7 ) &&
194 ( za >= -8 ) && ( za <= 7 ) &&
195 ( ya >= -16 ) && ( ya <= 15 ) )
196 {
197 // 4 bits each for x & z, and 5 for y
198 packet = shared_ptr<MoveEntityPacketSmall>( new MoveEntityPacketSmall::Pos(e->entityId, (char) xa, (char) ya, (char) za) );
199 c1a++;
200 }
201
202 else if( ( xa >= -16 ) && ( xa <= 15 ) &&
203 ( za >= -16 ) && ( za <= 15 ) &&
204 ( ya >= -32 ) && ( ya <= 31 ) )
205 {
206 // use the packet with small packet with rotation if we can - 5 bits each for x & z, and 6 for y - still a byte less than the alternative
207 packet = shared_ptr<MoveEntityPacketSmall>( new MoveEntityPacketSmall::PosRot(e->entityId, (char) xa, (char) ya, (char) za, 0, 0 ));
208 c1b++;
209 }
210 else
211 {
212 packet = shared_ptr<MoveEntityPacket>( new MoveEntityPacket::Pos(e->entityId, (char) xa, (char) ya, (char) za) );
213 c1c++;
214 }
215 }
216 else if (rot)
217 {
218 // 4J If there's no x rotation, then use the new smaller packet type
219 if( xRota == 0 )
220 {
221 // Clamp rotations that are too big
222 if( yRota < -16 )
223 {
224 yRota = -16;
225 yRotn = yRotp + yRota;
226 }
227 else if( yRota > 15 )
228 {
229 yRota = 15;
230 yRotn = yRotp + yRota;
231 }
232 packet = shared_ptr<MoveEntityPacketSmall>( new MoveEntityPacketSmall::Rot(e->entityId, (char) yRota, 0) );
233 c2a++;
234 }
235 else
236 {
237 // printf("%d: New rot %d + %d = %d\n",e->entityId,yRotp,yRota,yRotn);
238 packet = shared_ptr<MoveEntityPacket>( new MoveEntityPacket::Rot(e->entityId, (char) yRota, (char) xRota) );
239 c2b++;
240 }
241 }
242 }
243 }
244
245 if (trackDelta)
246 {
247 double xad = e->xd - xap;
248 double yad = e->yd - yap;
249 double zad = e->zd - zap;
250
251 double max = 0.02;
252
253 double diff = xad * xad + yad * yad + zad * zad;
254
255 if (diff > max * max || (diff > 0 && e->xd == 0 && e->yd == 0 && e->zd == 0))
256 {
257 xap = e->xd;
258 yap = e->yd;
259 zap = e->zd;
260 broadcast( shared_ptr<SetEntityMotionPacket>( new SetEntityMotionPacket(e->entityId, xap, yap, zap) ) );
261 }
262
263 }
264
265 if (packet != NULL)
266 {
267 broadcast(packet);
268 }
269
270 sendDirtyEntityData();
271
272 if (pos)
273 {
274 xp = xn;
275 yp = yn;
276 zp = zn;
277 }
278 if (rot)
279 {
280 yRotp = yRotn;
281 xRotp = xRotn;
282 }
283
284 wasRiding = false;
285 }
286 else
287 {
288 bool rot = abs(yRotn - yRotp) >= TOLERANCE_LEVEL || abs(xRotn - xRotp) >= TOLERANCE_LEVEL;
289 if (rot)
290 {
291 // 4J: Changed this to use deltas
292 broadcast( shared_ptr<MoveEntityPacket>( new MoveEntityPacket::Rot(e->entityId, (byte) yRota, (byte) xRota)) );
293 yRotp = yRotn;
294 xRotp = xRotn;
295 }
296
297 xp = Mth::floor(e->x * 32.0);
298 yp = Mth::floor(e->y * 32.0);
299 zp = Mth::floor(e->z * 32.0);
300
301 sendDirtyEntityData();
302
303 wasRiding = true;
304 }
305
306 int yHeadRot = Mth::floor(e->getYHeadRot() * 256 / 360);
307 if (abs(yHeadRot - yHeadRotp) >= TOLERANCE_LEVEL)
308 {
309 broadcast(shared_ptr<RotateHeadPacket>( new RotateHeadPacket(e->entityId, (byte) yHeadRot)));
310 yHeadRotp = yHeadRot;
311 }
312
313 e->hasImpulse = false;
314 }
315
316 tickCount++;
317
318 if (e->hurtMarked)
319 {
320 // broadcast(new AnimatePacket(e, AnimatePacket.HURT));
321 broadcastAndSend( shared_ptr<SetEntityMotionPacket>( new SetEntityMotionPacket(e) ) );
322 e->hurtMarked = false;
323 }
324
325}
326
327void TrackedEntity::sendDirtyEntityData()
328{
329 shared_ptr<SynchedEntityData> entityData = e->getEntityData();
330 if (entityData->isDirty())
331 {
332 broadcastAndSend( shared_ptr<SetEntityDataPacket>( new SetEntityDataPacket(e->entityId, entityData, false)) );
333 }
334
335 if ( e->instanceof(eTYPE_LIVINGENTITY) )
336 {
337 shared_ptr<LivingEntity> living = dynamic_pointer_cast<LivingEntity>(e);
338 ServersideAttributeMap *attributeMap = (ServersideAttributeMap *) living->getAttributes();
339 unordered_set<AttributeInstance *> *attributes = attributeMap->getDirtyAttributes();
340
341 if (!attributes->empty())
342 {
343 broadcastAndSend(shared_ptr<UpdateAttributesPacket>( new UpdateAttributesPacket(e->entityId, attributes)) );
344 }
345
346 attributes->clear();
347 }
348}
349
350void TrackedEntity::broadcast(shared_ptr<Packet> packet)
351{
352 if( Packet::canSendToAnyClient( packet ) )
353 {
354 // 4J-PB - due to the knockback on a player being hit, we need to send to all players, but limit the network traffic here to players that have not already had it sent to their system
355 vector< shared_ptr<ServerPlayer> > sentTo;
356
357 // 4J - don't send to a player we've already sent this data to that shares the same machine.
358 // EntityMotionPacket used to limit themselves to sending once to each machine
359 // by only sending to the primary player on each machine. This was causing trouble for split screen
360 // as only the primary player would get a knockback velocity. Now these packets can be sent to any
361 // player, but we try to restrict the network impact this has by not resending to the one machine
362
363 for( AUTO_VAR(it, seenBy.begin()); it != seenBy.end(); it++ )
364 {
365 shared_ptr<ServerPlayer> player = *it;
366 bool dontSend = false;
367 if( sentTo.size() )
368 {
369 INetworkPlayer *thisPlayer =player->connection->getNetworkPlayer();
370 if( thisPlayer == NULL )
371 {
372 dontSend = true;
373 }
374 else
375 {
376 for(unsigned int j = 0; j < sentTo.size(); j++ )
377 {
378 shared_ptr<ServerPlayer> player2 = sentTo[j];
379 INetworkPlayer *otherPlayer = player2->connection->getNetworkPlayer();
380 if( otherPlayer != NULL && thisPlayer->IsSameSystem(otherPlayer) )
381 {
382 dontSend = true;
383 // #ifdef _DEBUG
384 // shared_ptr<SetEntityMotionPacket> emp= dynamic_pointer_cast<SetEntityMotionPacket> (packet);
385 // if(emp!=NULL)
386 // {
387 // app.DebugPrintf("Not sending this SetEntityMotionPacket to player - it's already been sent to a player on their console\n");
388 // }
389 // #endif
390 }
391 }
392 }
393 }
394 if( dontSend )
395 {
396 continue;
397 }
398
399
400 (*it)->connection->send(packet);
401 sentTo.push_back(player);
402 }
403 }
404 else
405 {
406 // This packet hasn't got canSendToAnyClient set, so just send to everyone here, and it
407
408 for( AUTO_VAR(it, seenBy.begin()); it != seenBy.end(); it++ )
409 {
410 (*it)->connection->send(packet);
411 }
412 }
413}
414
415void TrackedEntity::broadcastAndSend(shared_ptr<Packet> packet)
416{
417 vector< shared_ptr<ServerPlayer> > sentTo;
418 broadcast(packet);
419 shared_ptr<ServerPlayer> sp = e->instanceof(eTYPE_SERVERPLAYER) ? dynamic_pointer_cast<ServerPlayer>(e) : nullptr;
420 if (sp != NULL && sp->connection)
421 {
422 sp->connection->send(packet);
423 }
424}
425
426void TrackedEntity::broadcastRemoved()
427{
428 for( AUTO_VAR(it, seenBy.begin()); it != seenBy.end(); it++ )
429 {
430 (*it)->entitiesToRemove.push_back(e->entityId);
431 }
432}
433
434void TrackedEntity::removePlayer(shared_ptr<ServerPlayer> sp)
435{
436 AUTO_VAR(it, seenBy.find( sp ));
437 if( it != seenBy.end() )
438 {
439 sp->entitiesToRemove.push_back(e->entityId);
440 seenBy.erase( it );
441 }
442}
443
444// 4J-JEV: Added for code reuse.
445TrackedEntity::eVisibility TrackedEntity::isVisible(EntityTracker *tracker, shared_ptr<ServerPlayer> sp, bool forRider)
446{
447 // 4J Stu - We call update players when the entity has moved more than a certain amount at the start of it's tick
448 // Before this call we set xpu, ypu and zpu to the entities new position, but xp,yp and zp are the old position until later in the tick.
449 // Therefore we should use the new position for visibility checks
450 double xd = sp->x - xpu; //xp / 32;
451 double zd = sp->z - zpu; //zp / 32;
452
453 // 4J Stu - Fix for loading a player who is currently riding something (e.g. a horse)
454 if(e->forcedLoading)
455 {
456 xd = sp->x - xp / 32;
457 zd = sp->z - zp / 32;
458 }
459
460 int playersRange = range;
461 if( playersRange > TRACKED_ENTITY_MINIMUM_VIEW_DISTANCE )
462 {
463 playersRange -= sp->getPlayerViewDistanceModifier();
464 }
465
466 bool bVisible = xd >= -playersRange && xd <= playersRange && zd >= -playersRange && zd <= playersRange;
467 bool canBeSeenBy = canBySeenBy(sp);
468
469 // 4J - added. Try and find other players who are in the same dimension as this one and on the same machine, and extend our visibility
470 // so things are consider visible to this player if they are near the other one. This is because we only send entity tracking info to
471 // players who canReceiveAllPackets().
472 if(!bVisible)
473 {
474 MinecraftServer *server = MinecraftServer::getInstance();
475 INetworkPlayer *thisPlayer = sp->connection->getNetworkPlayer();
476 if( thisPlayer )
477 {
478 for( unsigned int i = 0; i < server->getPlayers()->players.size(); i++ )
479 {
480 // Consider extra players, but not if they are the entity we are tracking, or the player we've been passed as input, or in another dimension
481 shared_ptr<ServerPlayer> ep = server->getPlayers()->players[i];
482 if( ep == sp ) continue;
483 if( ep == e ) continue;
484 if( ep->dimension != sp->dimension ) continue;
485
486 INetworkPlayer * otherPlayer = ep->connection->getNetworkPlayer();
487 if( otherPlayer != NULL && thisPlayer->IsSameSystem(otherPlayer) )
488 {
489 // 4J Stu - We call update players when the entity has moved more than a certain amount at the start of it's tick
490 // Before this call we set xpu, ypu and zpu to the entities new position, but xp,yp and zp are the old position until later in the tick.
491 // Therefore we should use the new position for visibility checks
492 double xd = ep->x - xpu; //xp / 32;
493 double zd = ep->z - zpu; //zp / 32;
494 bVisible |= ( xd >= -playersRange && xd <= playersRange && zd >= -playersRange && zd <= playersRange );
495 canBeSeenBy |= canBySeenBy(ep);
496 }
497 }
498 }
499 }
500
501 // 4J Stu - We need to ensure that we send the mount before the rider, so check that the player has been added to the seenBy list
502 if(forRider)
503 {
504 canBeSeenBy = canBeSeenBy && (seenBy.find(sp) != seenBy.end());
505 }
506
507 // 4J-JEV: ADDED! An entities mount has to be visible before the entity visible,
508 // this is to ensure that the mount is already in the client's game when the rider is added.
509 if (canBeSeenBy && bVisible && e->riding != NULL)
510 {
511 return tracker->getTracker(e->riding)->isVisible(tracker, sp, true);
512 }
513 else if (canBeSeenBy && bVisible) return eVisibility_SeenAndVisible;
514 else if (bVisible) return eVisibility_IsVisible;
515 else return eVisibility_NotVisible;
516}
517
518void TrackedEntity::updatePlayer(EntityTracker *tracker, shared_ptr<ServerPlayer> sp)
519{
520 if (sp == e) return;
521
522 eVisibility visibility = this->isVisible(tracker, sp);
523
524 if ( visibility == eVisibility_SeenAndVisible
525 && (seenBy.find(sp) == seenBy.end() || e->forcedLoading))
526 {
527 seenBy.insert(sp);
528 shared_ptr<Packet> packet = getAddEntityPacket();
529 sp->connection->send(packet);
530
531 xap = e->xd;
532 yap = e->yd;
533 zap = e->zd;
534
535 if ( e->instanceof(eTYPE_PLAYER) )
536 {
537 shared_ptr<Player> plr = dynamic_pointer_cast<Player>(e);
538 app.DebugPrintf( "TrackedEntity:: Player '%ls' is now visible to player '%ls', %s.\n",
539 plr->name.c_str(), sp->name.c_str(),
540 (e->riding==NULL?"not riding minecart":"in minecart")
541 );
542 }
543
544 bool isAddMobPacket = dynamic_pointer_cast<AddMobPacket>(packet) != NULL;
545
546 // 4J Stu brought forward to fix when Item Frames
547 if (!e->getEntityData()->isEmpty() && !isAddMobPacket)
548 {
549 sp->connection->send(shared_ptr<SetEntityDataPacket>( new SetEntityDataPacket(e->entityId, e->getEntityData(), true)));
550 }
551
552 if ( e->instanceof(eTYPE_LIVINGENTITY) )
553 {
554 shared_ptr<LivingEntity> living = dynamic_pointer_cast<LivingEntity>(e);
555 ServersideAttributeMap *attributeMap = (ServersideAttributeMap *) living->getAttributes();
556 unordered_set<AttributeInstance *> *attributes = attributeMap->getSyncableAttributes();
557
558 if (!attributes->empty())
559 {
560 sp->connection->send(shared_ptr<UpdateAttributesPacket>( new UpdateAttributesPacket(e->entityId, attributes)) );
561 }
562 delete attributes;
563 }
564
565 if (trackDelta && !isAddMobPacket)
566 {
567 sp->connection->send( shared_ptr<SetEntityMotionPacket>( new SetEntityMotionPacket(e->entityId, e->xd, e->yd, e->zd) ) );
568 }
569
570 if (e->riding != NULL)
571 {
572 sp->connection->send(shared_ptr<SetEntityLinkPacket>(new SetEntityLinkPacket(SetEntityLinkPacket::RIDING, e, e->riding)));
573 }
574 if ( e->instanceof(eTYPE_MOB) && dynamic_pointer_cast<Mob>(e)->getLeashHolder() != NULL)
575 {
576 sp->connection->send( shared_ptr<SetEntityLinkPacket>( new SetEntityLinkPacket(SetEntityLinkPacket::LEASH, e, dynamic_pointer_cast<Mob>(e)->getLeashHolder())) );
577 }
578
579 if ( e->instanceof(eTYPE_LIVINGENTITY) )
580 {
581 for (int i = 0; i < 5; i++)
582 {
583 shared_ptr<ItemInstance> item = dynamic_pointer_cast<LivingEntity>(e)->getCarried(i);
584 if(item != NULL) sp->connection->send( shared_ptr<SetEquippedItemPacket>( new SetEquippedItemPacket(e->entityId, i, item) ) );
585 }
586 }
587
588 if ( e->instanceof(eTYPE_PLAYER) )
589 {
590 shared_ptr<Player> spe = dynamic_pointer_cast<Player>(e);
591 if (spe->isSleeping())
592 {
593 sp->connection->send( shared_ptr<EntityActionAtPositionPacket>( new EntityActionAtPositionPacket(e, EntityActionAtPositionPacket::START_SLEEP, Mth::floor(e->x), Mth::floor(e->y), Mth::floor(e->z)) ) );
594 }
595 }
596
597 if ( e->instanceof(eTYPE_LIVINGENTITY) )
598 {
599 shared_ptr<LivingEntity> mob = dynamic_pointer_cast<LivingEntity>(e);
600 vector<MobEffectInstance *> *activeEffects = mob->getActiveEffects();
601 for(AUTO_VAR(it, activeEffects->begin()); it != activeEffects->end(); ++it)
602 {
603 MobEffectInstance *effect = *it;
604
605 sp->connection->send(shared_ptr<UpdateMobEffectPacket>( new UpdateMobEffectPacket(e->entityId, effect) ) );
606 }
607 delete activeEffects;
608 }
609 }
610 else if (visibility == eVisibility_NotVisible)
611 {
612 AUTO_VAR(it, seenBy.find(sp));
613 if (it != seenBy.end())
614 {
615 seenBy.erase(it);
616 sp->entitiesToRemove.push_back(e->entityId);
617 }
618 }
619
620}
621
622bool TrackedEntity::canBySeenBy(shared_ptr<ServerPlayer> player)
623{
624 // 4J - for some reason this isn't currently working, and is causing players to not appear until we are really close to them. Not sure
625 // what the conflict is between the java & our version, but removing for now as it is causing issues and we shouldn't *really* need it
626 // TODO - investigate further
627
628 return true;
629 // return player->getLevel()->getChunkMap()->isPlayerIn(player, e->xChunk, e->zChunk);
630}
631
632void TrackedEntity::updatePlayers(EntityTracker *tracker, vector<shared_ptr<Player> > *players)
633{
634 for (unsigned int i = 0; i < players->size(); i++)
635 {
636 updatePlayer(tracker, dynamic_pointer_cast<ServerPlayer>( players->at(i) ) );
637 }
638}
639
640shared_ptr<Packet> TrackedEntity::getAddEntityPacket()
641{
642 if (e->removed)
643 {
644 app.DebugPrintf("Fetching addPacket for removed entity - %ls\n", e->getAName().c_str());
645 }
646
647 // 4J-PB - replacing with a switch, rather than tons of ifs
648 if (dynamic_pointer_cast<Creature>(e) != NULL)
649 {
650 yHeadRotp = Mth::floor(e->getYHeadRot() * 256 / 360);
651 return shared_ptr<AddMobPacket>( new AddMobPacket(dynamic_pointer_cast<Mob>(e), yRotp, xRotp, xp, yp, zp, yHeadRotp) );
652 }
653
654 if (e->instanceof(eTYPE_ITEMENTITY))
655 {
656 shared_ptr<AddEntityPacket> packet = shared_ptr<AddEntityPacket>( new AddEntityPacket(e, AddEntityPacket::ITEM, 1, yRotp, xRotp, xp, yp, zp) );
657 return packet;
658 }
659 else if (e->instanceof(eTYPE_SERVERPLAYER))
660 {
661 shared_ptr<ServerPlayer> player = dynamic_pointer_cast<ServerPlayer>(e);
662
663 PlayerUID xuid = INVALID_XUID;
664 PlayerUID OnlineXuid = INVALID_XUID;
665 if( player != NULL )
666 {
667 xuid = player->getXuid();
668 OnlineXuid = player->getOnlineXuid();
669 }
670 // 4J Added yHeadRotp param to fix #102563 - TU12: Content: Gameplay: When one of the Players is idle for a few minutes his head turns 180 degrees.
671 return shared_ptr<AddPlayerPacket>( new AddPlayerPacket( player, xuid, OnlineXuid, xp, yp, zp, yRotp, xRotp, yHeadRotp ) );
672 }
673 else if (e->instanceof(eTYPE_MINECART))
674 {
675 shared_ptr<Minecart> minecart = dynamic_pointer_cast<Minecart>(e);
676 return shared_ptr<AddEntityPacket>( new AddEntityPacket(e, AddEntityPacket::MINECART, minecart->getType(), yRotp, xRotp, xp, yp, zp) );
677 }
678 else if (e->instanceof(eTYPE_BOAT))
679 {
680 return shared_ptr<AddEntityPacket>( new AddEntityPacket(e, AddEntityPacket::BOAT, yRotp, xRotp, xp, yp, zp) );
681 }
682 else if (e->instanceof(eTYPE_ENDERDRAGON))
683 {
684 yHeadRotp = Mth::floor(e->getYHeadRot() * 256 / 360);
685 return shared_ptr<AddMobPacket>( new AddMobPacket(dynamic_pointer_cast<LivingEntity>(e), yRotp, xRotp, xp, yp, zp, yHeadRotp ) );
686 }
687 else if (e->instanceof(eTYPE_FISHINGHOOK))
688 {
689 shared_ptr<Entity> owner = dynamic_pointer_cast<FishingHook>(e)->owner;
690 return shared_ptr<AddEntityPacket>( new AddEntityPacket(e, AddEntityPacket::FISH_HOOK, owner != NULL ? owner->entityId : e->entityId, yRotp, xRotp, xp, yp, zp) );
691 }
692 else if (e->instanceof(eTYPE_ARROW))
693 {
694 shared_ptr<Entity> owner = (dynamic_pointer_cast<Arrow>(e))->owner;
695 return shared_ptr<AddEntityPacket>( new AddEntityPacket(e, AddEntityPacket::ARROW, owner != NULL ? owner->entityId : e->entityId, yRotp, xRotp, xp, yp, zp) );
696 }
697 else if (e->instanceof(eTYPE_SNOWBALL))
698 {
699 return shared_ptr<AddEntityPacket>( new AddEntityPacket(e, AddEntityPacket::SNOWBALL, yRotp, xRotp, xp, yp, zp) );
700 }
701 else if (e->instanceof(eTYPE_THROWNPOTION))
702 {
703 return shared_ptr<AddEntityPacket>( new AddEntityPacket(e, AddEntityPacket::THROWN_POTION, ((dynamic_pointer_cast<ThrownPotion>(e))->getPotionValue()), yRotp, xRotp, xp, yp, zp));
704 }
705 else if (e->instanceof(eTYPE_THROWNEXPBOTTLE))
706 {
707 return shared_ptr<AddEntityPacket>( new AddEntityPacket(e, AddEntityPacket::THROWN_EXPBOTTLE, yRotp, xRotp, xp, yp, zp) );
708 }
709 else if (e->instanceof(eTYPE_THROWNENDERPEARL))
710 {
711 return shared_ptr<AddEntityPacket>( new AddEntityPacket(e, AddEntityPacket::THROWN_ENDERPEARL, yRotp, xRotp, xp, yp, zp) );
712 }
713 else if (e->instanceof(eTYPE_EYEOFENDERSIGNAL))
714 {
715 return shared_ptr<AddEntityPacket>( new AddEntityPacket(e, AddEntityPacket::EYEOFENDERSIGNAL, yRotp, xRotp, xp, yp, zp) );
716 }
717 else if (e->instanceof(eTYPE_FIREWORKS_ROCKET))
718 {
719 return shared_ptr<AddEntityPacket>( new AddEntityPacket(e, AddEntityPacket::FIREWORKS, yRotp, xRotp, xp, yp, zp) );
720 }
721 else if (e->instanceof(eTYPE_FIREBALL))
722 {
723 eINSTANCEOF classType = e->GetType();
724 int type = AddEntityPacket::FIREBALL;
725 if (classType == eTYPE_SMALL_FIREBALL)
726 {
727 type = AddEntityPacket::SMALL_FIREBALL;
728 }
729 else if (classType == eTYPE_DRAGON_FIREBALL)
730 {
731 type = AddEntityPacket::DRAGON_FIRE_BALL;
732 }
733 else if (classType == eTYPE_WITHER_SKULL)
734 {
735 type = AddEntityPacket::WITHER_SKULL;
736 }
737
738 shared_ptr<Fireball> fb = dynamic_pointer_cast<Fireball>(e);
739 shared_ptr<AddEntityPacket> aep = nullptr;
740 if (fb->owner != NULL)
741 {
742 aep = shared_ptr<AddEntityPacket>( new AddEntityPacket(e, type, fb->owner->entityId, yRotp, xRotp, xp, yp, zp) );
743 }
744 else
745 {
746 aep = shared_ptr<AddEntityPacket>( new AddEntityPacket(e, type, 0, yRotp, xRotp, xp, yp, zp) );
747 }
748 aep->xa = (int) (fb->xPower * 8000);
749 aep->ya = (int) (fb->yPower * 8000);
750 aep->za = (int) (fb->zPower * 8000);
751 return aep;
752 }
753 else if (e->instanceof(eTYPE_THROWNEGG))
754 {
755 return shared_ptr<AddEntityPacket>( new AddEntityPacket(e, AddEntityPacket::EGG, yRotp, xRotp, xp, yp, zp) );
756 }
757 else if (e->instanceof(eTYPE_PRIMEDTNT))
758 {
759 return shared_ptr<AddEntityPacket>( new AddEntityPacket(e, AddEntityPacket::PRIMED_TNT, yRotp, xRotp, xp, yp, zp) );
760 }
761 else if (e->instanceof(eTYPE_ENDER_CRYSTAL))
762 {
763 return shared_ptr<AddEntityPacket>( new AddEntityPacket(e, AddEntityPacket::ENDER_CRYSTAL, yRotp, xRotp, xp, yp, zp) );
764 }
765 else if (e->instanceof(eTYPE_FALLINGTILE))
766 {
767 shared_ptr<FallingTile> ft = dynamic_pointer_cast<FallingTile>(e);
768 return shared_ptr<AddEntityPacket>( new AddEntityPacket(e, AddEntityPacket::FALLING, ft->tile | (ft->data << 16), yRotp, xRotp, xp, yp, zp) );
769 }
770 else if (e->instanceof(eTYPE_PAINTING))
771 {
772 return shared_ptr<AddPaintingPacket>( new AddPaintingPacket(dynamic_pointer_cast<Painting>(e)) );
773 }
774 else if (e->instanceof(eTYPE_ITEM_FRAME))
775 {
776 shared_ptr<ItemFrame> frame = dynamic_pointer_cast<ItemFrame>(e);
777
778 {
779
780 int ix= (int)frame->xTile;
781 int iy= (int)frame->yTile;
782 int iz= (int)frame->zTile;
783 app.DebugPrintf("eTYPE_ITEM_FRAME xyz %d,%d,%d\n",ix,iy,iz);
784 }
785
786 shared_ptr<AddEntityPacket> packet = shared_ptr<AddEntityPacket>(new AddEntityPacket(e, AddEntityPacket::ITEM_FRAME, frame->dir, yRotp, xRotp, xp, yp, zp));
787 packet->x = Mth::floor(frame->xTile * 32.0f);
788 packet->y = Mth::floor(frame->yTile * 32.0f);
789 packet->z = Mth::floor(frame->zTile * 32.0f);
790 return packet;
791 }
792 else if (e->instanceof(eTYPE_LEASHFENCEKNOT))
793 {
794 shared_ptr<LeashFenceKnotEntity> knot = dynamic_pointer_cast<LeashFenceKnotEntity>(e);
795 shared_ptr<AddEntityPacket> packet = shared_ptr<AddEntityPacket>(new AddEntityPacket(e, AddEntityPacket::LEASH_KNOT, yRotp, xRotp, xp, yp, zp) );
796 packet->x = Mth::floor((float)knot->xTile * 32);
797 packet->y = Mth::floor((float)knot->yTile * 32);
798 packet->z = Mth::floor((float)knot->zTile * 32);
799 return packet;
800 }
801 else if (e->instanceof(eTYPE_EXPERIENCEORB))
802 {
803 return shared_ptr<AddExperienceOrbPacket>( new AddExperienceOrbPacket(dynamic_pointer_cast<ExperienceOrb>(e)) );
804 }
805 else
806 {
807 assert(false);
808 }
809
810 return nullptr;
811}
812
813void TrackedEntity::clear(shared_ptr<ServerPlayer> sp)
814{
815 AUTO_VAR(it, seenBy.find(sp));
816 if (it != seenBy.end())
817 {
818 seenBy.erase(it);
819 sp->entitiesToRemove.push_back(e->entityId);
820 }
821}