2026-03-01 12:16:08 +08:00
# include "stdafx.h"
# include "TrackedEntity.h"
# include "ServerPlayer.h"
# include "PlayerConnection.h"
# include "..\Minecraft.World\Mth.h"
# include "..\Minecraft.World\net.minecraft.world.entity.h"
# include "..\Minecraft.World\net.minecraft.world.entity.item.h"
# include "..\Minecraft.World\net.minecraft.world.entity.monster.h"
# include "..\Minecraft.World\net.minecraft.world.entity.player.h"
# include "..\Minecraft.World\net.minecraft.world.entity.animal.h"
# include "..\Minecraft.World\net.minecraft.world.entity.global.h"
# include "..\Minecraft.World\net.minecraft.world.entity.projectile.h"
# include "..\Minecraft.World\net.minecraft.network.packet.h"
# include "..\Minecraft.World\net.minecraft.world.item.h"
# include "..\Minecraft.World\net.minecraft.world.level.saveddata.h"
# include "MinecraftServer.h"
# include "ServerLevel.h"
# include "PlayerList.h"
# include "EntityTracker.h"
# include "PlayerChunkMap.h"
# include <qnet.h>
2026-03-02 15:58:20 +07:00
TrackedEntity : : TrackedEntity ( std : : shared_ptr < Entity > e , int range , int updateInterval , bool trackDelta )
2026-03-01 12:16:08 +08:00
{
// 4J added initialisers
xap = yap = zap = 0 ;
tickCount = 0 ;
xpu = ypu = zpu = 0 ;
updatedPlayerVisibility = false ;
teleportDelay = 0 ;
moved = false ;
2026-03-02 15:58:20 +07:00
2026-03-01 12:16:08 +08:00
this - > e = e ;
this - > range = range ;
this - > updateInterval = updateInterval ;
this - > trackDelta = trackDelta ;
xp = Mth : : floor ( e - > x * 32 ) ;
yp = Mth : : floor ( e - > y * 32 ) ;
zp = Mth : : floor ( e - > z * 32 ) ;
yRotp = Mth : : floor ( e - > yRot * 256 / 360 ) ;
xRotp = Mth : : floor ( e - > xRot * 256 / 360 ) ;
yHeadRotp = Mth : : floor ( e - > getYHeadRot ( ) * 256 / 360 ) ;
}
int c0a = 0 , c0b = 0 , c1a = 0 , c1b = 0 , c1c = 0 , c2a = 0 , c2b = 0 ;
2026-03-02 15:58:20 +07:00
void TrackedEntity : : tick ( EntityTracker * tracker , vector < std : : shared_ptr < Player > > * players )
2026-03-01 12:16:08 +08:00
{
moved = false ;
if ( ! updatedPlayerVisibility | | e - > distanceToSqr ( xpu , ypu , zpu ) > 4 * 4 )
{
xpu = e - > x ;
ypu = e - > y ;
zpu = e - > z ;
updatedPlayerVisibility = true ;
moved = true ;
updatePlayers ( tracker , players ) ;
}
if ( wasRiding ! = e - > riding )
{
wasRiding = e - > riding ;
2026-03-02 15:58:20 +07:00
broadcast ( std : : shared_ptr < SetRidingPacket > ( new SetRidingPacket ( e , e - > riding ) ) ) ;
2026-03-01 12:16:08 +08:00
}
// Moving forward special case for item frames
2026-03-02 15:58:20 +07:00
if ( e - > GetType ( ) = = eTYPE_ITEM_FRAME & & tickCount % 10 = = 0 )
2026-03-01 12:16:08 +08:00
{
2026-03-02 15:58:20 +07:00
std : : shared_ptr < ItemFrame > frame = dynamic_pointer_cast < ItemFrame > ( e ) ;
std : : shared_ptr < ItemInstance > item = frame - > getItem ( ) ;
2026-03-01 12:16:08 +08:00
2026-03-02 15:58:20 +07:00
if ( item ! = NULL & & item - > getItem ( ) - > id = = Item : : map_Id & & ! e - > removed )
2026-03-01 12:16:08 +08:00
{
2026-03-02 15:58:20 +07:00
std : : shared_ptr < MapItemSavedData > data = Item : : map - > getSavedData ( item , e - > level ) ;
2026-03-01 12:16:08 +08:00
for ( AUTO_VAR ( it , players - > begin ( ) ) ; it ! = players - > end ( ) ; + + it )
{
2026-03-02 15:58:20 +07:00
std : : shared_ptr < ServerPlayer > player = dynamic_pointer_cast < ServerPlayer > ( * it ) ;
2026-03-01 12:16:08 +08:00
data - > tickCarriedBy ( player , item ) ;
2026-03-02 15:58:20 +07:00
if ( ! player - > removed & & player - > connection & & player - > connection - > countDelayedPackets ( ) < = 5 )
2026-03-01 12:16:08 +08:00
{
2026-03-02 15:58:20 +07:00
std : : shared_ptr < Packet > packet = Item : : map - > getUpdatePacket ( item , e - > level , player ) ;
2026-03-01 12:16:08 +08:00
if ( packet ! = NULL ) player - > connection - > send ( packet ) ;
}
}
}
2026-03-02 15:58:20 +07:00
std : : shared_ptr < SynchedEntityData > entityData = e - > getEntityData ( ) ;
if ( entityData - > isDirty ( ) )
2026-03-01 12:16:08 +08:00
{
2026-03-02 15:58:20 +07:00
broadcastAndSend ( std : : shared_ptr < SetEntityDataPacket > ( new SetEntityDataPacket ( e - > entityId , entityData , false ) ) ) ;
2026-03-01 12:16:08 +08:00
}
}
else
{
if ( e - > riding = = NULL )
{
teleportDelay + + ;
if ( tickCount + + % updateInterval = = 0 | | e - > hasImpulse )
{
int xn = Mth : : floor ( this - > e - > x * 32.0 ) ;
int yn = Mth : : floor ( this - > e - > y * 32.0 ) ;
int zn = Mth : : floor ( this - > e - > z * 32.0 ) ;
int yRotn = Mth : : floor ( e - > yRot * 256 / 360 ) ;
int xRotn = Mth : : floor ( e - > xRot * 256 / 360 ) ;
int xa = xn - xp ;
int ya = yn - yp ;
int za = zn - zp ;
2026-03-02 15:58:20 +07:00
std : : shared_ptr < Packet > packet = nullptr ;
2026-03-01 12:16:08 +08:00
// 4J - this pos flag used to be set based on abs(xn) etc. but that just seems wrong
bool pos = abs ( xa ) > = TOLERANCE_LEVEL | | abs ( ya ) > = TOLERANCE_LEVEL | | abs ( za ) > = TOLERANCE_LEVEL ;
// 4J - changed rotation to be generally sent as a delta as well as position
int yRota = yRotn - yRotp ;
int xRota = xRotn - xRotp ;
2026-03-02 15:58:20 +07:00
// Keep rotation deltas in +/- 180 degree range
2026-03-01 12:16:08 +08:00
while ( yRota > 127 ) yRota - = 256 ;
while ( yRota < - 128 ) yRota + = 256 ;
while ( xRota > 127 ) xRota - = 256 ;
while ( xRota < - 128 ) xRota + = 256 ;
bool rot = abs ( yRota ) > = TOLERANCE_LEVEL | | abs ( xRota ) > = TOLERANCE_LEVEL ;
if ( xa < - 128 | | xa > = 128 | | ya < - 128 | | ya > = 128 | | za < - 128 | | za > = 128
// 4J Stu - I fixed the initialisation of teleportDelay in the ctor, but we managed this far without out
// and would prefer not to have all the extra traffix so ignore it
// 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.
| | ( e - > GetType ( ) = = eTYPE_BOAT & & teleportDelay > 20 * 20 )
)
{
teleportDelay = 0 ;
2026-03-02 15:58:20 +07:00
packet = std : : shared_ptr < TeleportEntityPacket > ( new TeleportEntityPacket ( e - > entityId , xn , yn , zn , ( byte ) yRotn , ( byte ) xRotn ) ) ;
2026-03-01 12:16:08 +08:00
// printf("%d: New teleport rot %d\n",e->entityId,yRotn);
yRotp = yRotn ;
xRotp = xRotn ;
}
else
{
if ( pos & & rot )
{
// 4J If the movement is small enough, and there's no xrot, then use the new smaller packets
if ( ( xa > = - 16 ) & & ( xa < = 15 ) & &
( za > = - 16 ) & & ( za < = 15 ) & &
( ya > = - 32 ) & & ( ya < = 31 ) & &
( xRota = = 0 ) )
{
// Clamp rotations that are too big
if ( yRota < - 16 )
{
yRota = - 16 ;
yRotn = yRotp + yRota ;
}
else if ( yRota > 15 )
{
yRota = 15 ;
yRotn = yRotp + yRota ;
}
// 5 bits each for x & z, and 6 for y
2026-03-02 15:58:20 +07:00
packet = std : : shared_ptr < MoveEntityPacketSmall > ( new MoveEntityPacketSmall : : PosRot ( e - > entityId , ( char ) xa , ( char ) ya , ( char ) za , ( char ) yRota , 0 ) ) ;
2026-03-01 12:16:08 +08:00
c0a + + ;
}
else
{
2026-03-02 15:58:20 +07:00
packet = std : : shared_ptr < MoveEntityPacket > ( new MoveEntityPacket : : PosRot ( e - > entityId , ( char ) xa , ( char ) ya , ( char ) za , ( char ) yRota , ( char ) xRota ) ) ;
2026-03-01 12:16:08 +08:00
// printf("%d: New posrot %d + %d = %d\n",e->entityId,yRotp,yRota,yRotn);
c0b + + ;
}
}
else if ( pos )
{
// 4J If the movement is small enough, then use the new smaller packets
if ( ( xa > = - 8 ) & & ( xa < = 7 ) & &
( za > = - 8 ) & & ( za < = 7 ) & &
( ya > = - 16 ) & & ( ya < = 15 ) )
{
// 4 bits each for x & z, and 5 for y
2026-03-02 15:58:20 +07:00
packet = std : : shared_ptr < MoveEntityPacketSmall > ( new MoveEntityPacketSmall : : Pos ( e - > entityId , ( char ) xa , ( char ) ya , ( char ) za ) ) ;
2026-03-01 12:16:08 +08:00
c1a + + ;
}
else if ( ( xa > = - 16 ) & & ( xa < = 15 ) & &
( za > = - 16 ) & & ( za < = 15 ) & &
( ya > = - 32 ) & & ( ya < = 31 ) )
{
// 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
2026-03-02 15:58:20 +07:00
packet = std : : shared_ptr < MoveEntityPacketSmall > ( new MoveEntityPacketSmall : : PosRot ( e - > entityId , ( char ) xa , ( char ) ya , ( char ) za , 0 , 0 ) ) ;
2026-03-01 12:16:08 +08:00
c1b + + ;
}
else
{
2026-03-02 15:58:20 +07:00
packet = std : : shared_ptr < MoveEntityPacket > ( new MoveEntityPacket : : Pos ( e - > entityId , ( char ) xa , ( char ) ya , ( char ) za ) ) ;
2026-03-01 12:16:08 +08:00
c1c + + ;
}
}
else if ( rot )
{
// 4J If there's no x rotation, then use the new smaller packet type
if ( xRota = = 0 )
{
// Clamp rotations that are too big
if ( yRota < - 16 )
{
yRota = - 16 ;
yRotn = yRotp + yRota ;
}
else if ( yRota > 15 )
{
yRota = 15 ;
yRotn = yRotp + yRota ;
}
2026-03-02 15:58:20 +07:00
packet = std : : shared_ptr < MoveEntityPacketSmall > ( new MoveEntityPacketSmall : : Rot ( e - > entityId , ( char ) yRota , 0 ) ) ;
2026-03-01 12:16:08 +08:00
c2a + + ;
}
else
{
// printf("%d: New rot %d + %d = %d\n",e->entityId,yRotp,yRota,yRotn);
2026-03-02 15:58:20 +07:00
packet = std : : shared_ptr < MoveEntityPacket > ( new MoveEntityPacket : : Rot ( e - > entityId , ( char ) yRota , ( char ) xRota ) ) ;
2026-03-01 12:16:08 +08:00
c2b + + ;
}
}
}
if ( trackDelta )
{
double xad = e - > xd - xap ;
double yad = e - > yd - yap ;
double zad = e - > zd - zap ;
double max = 0.02 ;
double diff = xad * xad + yad * yad + zad * zad ;
if ( diff > max * max | | ( diff > 0 & & e - > xd = = 0 & & e - > yd = = 0 & & e - > zd = = 0 ) )
{
xap = e - > xd ;
yap = e - > yd ;
zap = e - > zd ;
2026-03-02 15:58:20 +07:00
broadcast ( std : : shared_ptr < SetEntityMotionPacket > ( new SetEntityMotionPacket ( e - > entityId , xap , yap , zap ) ) ) ;
2026-03-01 12:16:08 +08:00
}
}
if ( packet ! = NULL )
{
broadcast ( packet ) ;
}
2026-03-02 15:58:20 +07:00
std : : shared_ptr < SynchedEntityData > entityData = e - > getEntityData ( ) ;
2026-03-01 12:16:08 +08:00
if ( entityData - > isDirty ( ) )
{
2026-03-02 15:58:20 +07:00
broadcastAndSend ( std : : shared_ptr < SetEntityDataPacket > ( new SetEntityDataPacket ( e - > entityId , entityData , false ) ) ) ;
2026-03-01 12:16:08 +08:00
}
int yHeadRot = Mth : : floor ( e - > getYHeadRot ( ) * 256 / 360 ) ;
if ( abs ( yHeadRot - yHeadRotp ) > = TOLERANCE_LEVEL )
{
2026-03-02 15:58:20 +07:00
broadcast ( std : : shared_ptr < RotateHeadPacket > ( new RotateHeadPacket ( e - > entityId , ( byte ) yHeadRot ) ) ) ;
2026-03-01 12:16:08 +08:00
yHeadRotp = yHeadRot ;
}
if ( pos )
{
xp = xn ;
yp = yn ;
zp = zn ;
}
if ( rot )
{
yRotp = yRotn ;
xRotp = xRotn ;
}
// if( dynamic_pointer_cast<ServerPlayer>(e) != NULL )
// {
// printf("%d: %d + %d = %d (%f)\n",e->entityId,xRotp,xRota,xRotn,e->xRot);
// }
}
2026-03-02 15:58:20 +07:00
2026-03-01 12:16:08 +08:00
}
else // 4J-JEV: Added: Mobs in minecarts weren't synching their invisibility.
{
2026-03-02 15:58:20 +07:00
std : : shared_ptr < SynchedEntityData > entityData = e - > getEntityData ( ) ;
2026-03-01 12:16:08 +08:00
if ( entityData - > isDirty ( ) )
2026-03-02 15:58:20 +07:00
broadcastAndSend ( std : : shared_ptr < SetEntityDataPacket > ( new SetEntityDataPacket ( e - > entityId , entityData , false ) ) ) ;
2026-03-01 12:16:08 +08:00
}
e - > hasImpulse = false ;
}
if ( e - > hurtMarked )
{
// broadcast(new AnimatePacket(e, AnimatePacket.HURT));
2026-03-02 15:58:20 +07:00
broadcastAndSend ( std : : shared_ptr < SetEntityMotionPacket > ( new SetEntityMotionPacket ( e ) ) ) ;
2026-03-01 12:16:08 +08:00
e - > hurtMarked = false ;
}
}
2026-03-02 15:58:20 +07:00
void TrackedEntity : : broadcast ( std : : shared_ptr < Packet > packet )
2026-03-01 12:16:08 +08:00
{
if ( Packet : : canSendToAnyClient ( packet ) )
{
// 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
2026-03-02 15:58:20 +07:00
vector < std : : shared_ptr < ServerPlayer > > sentTo ;
2026-03-01 12:16:08 +08:00
2026-03-02 15:58:20 +07:00
// 4J - don't send to a player we've already sent this data to that shares the same machine.
2026-03-01 12:16:08 +08:00
// EntityMotionPacket used to limit themselves to sending once to each machine
// by only sending to the primary player on each machine. This was causing trouble for split screen
// as only the primary player would get a knockback velocity. Now these packets can be sent to any
// player, but we try to restrict the network impact this has by not resending to the one machine
for ( AUTO_VAR ( it , seenBy . begin ( ) ) ; it ! = seenBy . end ( ) ; it + + )
{
2026-03-02 15:58:20 +07:00
std : : shared_ptr < ServerPlayer > player = * it ;
2026-03-01 12:16:08 +08:00
bool dontSend = false ;
if ( sentTo . size ( ) )
{
INetworkPlayer * thisPlayer = player - > connection - > getNetworkPlayer ( ) ;
if ( thisPlayer = = NULL )
{
dontSend = true ;
}
else
{
2026-03-02 15:58:20 +07:00
for ( unsigned int j = 0 ; j < sentTo . size ( ) ; j + + )
2026-03-01 12:16:08 +08:00
{
2026-03-02 15:58:20 +07:00
std : : shared_ptr < ServerPlayer > player2 = sentTo [ j ] ;
2026-03-01 12:16:08 +08:00
INetworkPlayer * otherPlayer = player2 - > connection - > getNetworkPlayer ( ) ;
if ( otherPlayer ! = NULL & & thisPlayer - > IsSameSystem ( otherPlayer ) )
{
dontSend = true ;
// #ifdef _DEBUG
2026-03-02 15:58:20 +07:00
// std::shared_ptr<SetEntityMotionPacket> emp= dynamic_pointer_cast<SetEntityMotionPacket> (packet);
2026-03-01 12:16:08 +08:00
// if(emp!=NULL)
// {
// app.DebugPrintf("Not sending this SetEntityMotionPacket to player - it's already been sent to a player on their console\n");
// }
// #endif
}
}
}
}
if ( dontSend )
{
continue ;
}
( * it ) - > connection - > send ( packet ) ;
sentTo . push_back ( player ) ;
}
}
else
{
// This packet hasn't got canSendToAnyClient set, so just send to everyone here, and it
for ( AUTO_VAR ( it , seenBy . begin ( ) ) ; it ! = seenBy . end ( ) ; it + + )
{
( * it ) - > connection - > send ( packet ) ;
}
}
}
2026-03-02 15:58:20 +07:00
void TrackedEntity : : broadcastAndSend ( std : : shared_ptr < Packet > packet )
2026-03-01 12:16:08 +08:00
{
2026-03-02 15:58:20 +07:00
vector < std : : shared_ptr < ServerPlayer > > sentTo ;
2026-03-01 12:16:08 +08:00
broadcast ( packet ) ;
2026-03-02 15:58:20 +07:00
std : : shared_ptr < ServerPlayer > sp = dynamic_pointer_cast < ServerPlayer > ( e ) ;
2026-03-01 12:16:08 +08:00
if ( sp ! = NULL & & sp - > connection )
{
sp - > connection - > send ( packet ) ;
}
}
void TrackedEntity : : broadcastRemoved ( )
{
for ( AUTO_VAR ( it , seenBy . begin ( ) ) ; it ! = seenBy . end ( ) ; it + + )
{
( * it ) - > entitiesToRemove . push_back ( e - > entityId ) ;
}
}
2026-03-02 15:58:20 +07:00
void TrackedEntity : : removePlayer ( std : : shared_ptr < ServerPlayer > sp )
2026-03-01 12:16:08 +08:00
{
AUTO_VAR ( it , seenBy . find ( sp ) ) ;
if ( it ! = seenBy . end ( ) )
{
seenBy . erase ( it ) ;
}
}
// 4J-JEV: Added for code reuse.
2026-03-02 15:58:20 +07:00
TrackedEntity : : eVisibility TrackedEntity : : isVisible ( EntityTracker * tracker , std : : shared_ptr < ServerPlayer > sp , bool forRider )
2026-03-01 12:16:08 +08:00
{
// 4J Stu - We call update players when the entity has moved more than a certain amount at the start of it's tick
// 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.
// Therefore we should use the new position for visibility checks
double xd = sp - > x - xpu ; //xp / 32;
double zd = sp - > z - zpu ; //zp / 32;
int playersRange = range ;
if ( playersRange > TRACKED_ENTITY_MINIMUM_VIEW_DISTANCE )
{
playersRange - = sp - > getPlayerViewDistanceModifier ( ) ;
}
bool bVisible = xd > = - playersRange & & xd < = playersRange & & zd > = - playersRange & & zd < = playersRange ;
bool canBeSeenBy = canBySeenBy ( sp ) ;
// 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
// 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
// players who canReceiveAllPackets().
if ( ! bVisible )
{
MinecraftServer * server = MinecraftServer : : getInstance ( ) ;
INetworkPlayer * thisPlayer = sp - > connection - > getNetworkPlayer ( ) ;
if ( thisPlayer )
{
for ( unsigned int i = 0 ; i < server - > getPlayers ( ) - > players . size ( ) ; i + + )
{
// 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
2026-03-02 15:58:20 +07:00
std : : shared_ptr < ServerPlayer > ep = server - > getPlayers ( ) - > players [ i ] ;
2026-03-01 12:16:08 +08:00
if ( ep = = sp ) continue ;
if ( ep = = e ) continue ;
if ( ep - > dimension ! = sp - > dimension ) continue ;
INetworkPlayer * otherPlayer = ep - > connection - > getNetworkPlayer ( ) ;
if ( otherPlayer ! = NULL & & thisPlayer - > IsSameSystem ( otherPlayer ) )
{
// 4J Stu - We call update players when the entity has moved more than a certain amount at the start of it's tick
// 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.
// Therefore we should use the new position for visibility checks
double xd = ep - > x - xpu ; //xp / 32;
double zd = ep - > z - zpu ; //zp / 32;
bVisible | = ( xd > = - playersRange & & xd < = playersRange & & zd > = - playersRange & & zd < = playersRange ) ;
canBeSeenBy | = canBySeenBy ( ep ) ;
}
}
}
}
// 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
if ( forRider )
{
canBeSeenBy = canBeSeenBy & & ( seenBy . find ( sp ) ! = seenBy . end ( ) ) ;
}
// 4J-JEV: ADDED! An entities mount has to be visible before the entity visible,
// this is to ensure that the mount is already in the client's game when the rider is added.
if ( canBeSeenBy & & bVisible & & e - > riding ! = NULL )
{
return tracker - > getTracker ( e - > riding ) - > isVisible ( tracker , sp , true ) ;
}
else if ( canBeSeenBy & & bVisible ) return eVisibility_SeenAndVisible ;
else if ( bVisible ) return eVisibility_IsVisible ;
else return eVisibility_NotVisible ;
}
2026-03-02 15:58:20 +07:00
void TrackedEntity : : updatePlayer ( EntityTracker * tracker , std : : shared_ptr < ServerPlayer > sp )
2026-03-01 12:16:08 +08:00
{
if ( sp = = e ) return ;
eVisibility visibility = this - > isVisible ( tracker , sp ) ;
2026-03-02 15:58:20 +07:00
2026-03-01 12:16:08 +08:00
if ( visibility = = eVisibility_SeenAndVisible
& & seenBy . find ( sp ) = = seenBy . end ( ) )
{
seenBy . insert ( sp ) ;
2026-03-02 15:58:20 +07:00
std : : shared_ptr < Packet > packet = getAddEntityPacket ( ) ;
2026-03-01 12:16:08 +08:00
sp - > connection - > send ( packet ) ;
xap = e - > xd ;
yap = e - > yd ;
zap = e - > zd ;
2026-03-02 15:58:20 +07:00
std : : shared_ptr < Player > plr = dynamic_pointer_cast < Player > ( e ) ;
2026-03-01 12:16:08 +08:00
if ( plr ! = NULL )
{
app . DebugPrintf ( " TrackedEntity:: Player '%ls' is now visible to player '%ls', %s. \n " ,
plr - > name . c_str ( ) , sp - > name . c_str ( ) ,
( e - > riding = = NULL ? " not riding minecart " : " in minecart " )
) ;
}
// 4J Stu brought forward to fix when Item Frames
if ( ! e - > getEntityData ( ) - > isEmpty ( ) & & ! ( dynamic_pointer_cast < AddMobPacket > ( packet ) ) )
{
2026-03-02 15:58:20 +07:00
sp - > connection - > send ( std : : shared_ptr < SetEntityDataPacket > ( new SetEntityDataPacket ( e - > entityId , e - > getEntityData ( ) , true ) ) ) ;
2026-03-01 12:16:08 +08:00
}
if ( this - > trackDelta )
{
2026-03-02 15:58:20 +07:00
sp - > connection - > send ( std : : shared_ptr < SetEntityMotionPacket > ( new SetEntityMotionPacket ( e - > entityId , e - > xd , e - > yd , e - > zd ) ) ) ;
2026-03-01 12:16:08 +08:00
}
if ( e - > riding ! = NULL )
{
2026-03-02 15:58:20 +07:00
sp - > connection - > send ( std : : shared_ptr < SetRidingPacket > ( new SetRidingPacket ( e , e - > riding ) ) ) ;
2026-03-01 12:16:08 +08:00
}
ItemInstanceArray equipped = e - > getEquipmentSlots ( ) ;
if ( equipped . data ! = NULL )
{
for ( unsigned int i = 0 ; i < equipped . length ; i + + )
{
2026-03-02 15:58:20 +07:00
sp - > connection - > send ( std : : shared_ptr < SetEquippedItemPacket > ( new SetEquippedItemPacket ( e - > entityId , i , equipped [ i ] ) ) ) ;
2026-03-01 12:16:08 +08:00
}
}
if ( dynamic_pointer_cast < Player > ( e ) ! = NULL )
{
2026-03-02 15:58:20 +07:00
std : : shared_ptr < Player > spe = dynamic_pointer_cast < Player > ( e ) ;
2026-03-01 12:16:08 +08:00
if ( spe - > isSleeping ( ) )
{
2026-03-02 15:58:20 +07:00
sp - > connection - > send ( std : : shared_ptr < EntityActionAtPositionPacket > ( new EntityActionAtPositionPacket ( e , EntityActionAtPositionPacket : : START_SLEEP , Mth : : floor ( e - > x ) , Mth : : floor ( e - > y ) , Mth : : floor ( e - > z ) ) ) ) ;
2026-03-01 12:16:08 +08:00
}
}
if ( dynamic_pointer_cast < Mob > ( e ) ! = NULL )
{
2026-03-02 15:58:20 +07:00
std : : shared_ptr < Mob > mob = dynamic_pointer_cast < Mob > ( e ) ;
2026-03-01 12:16:08 +08:00
vector < MobEffectInstance * > * activeEffects = mob - > getActiveEffects ( ) ;
for ( AUTO_VAR ( it , activeEffects - > begin ( ) ) ; it ! = activeEffects - > end ( ) ; + + it )
{
MobEffectInstance * effect = * it ;
2026-03-02 15:58:20 +07:00
sp - > connection - > send ( std : : shared_ptr < UpdateMobEffectPacket > ( new UpdateMobEffectPacket ( e - > entityId , effect ) ) ) ;
2026-03-01 12:16:08 +08:00
}
delete activeEffects ;
}
}
else if ( visibility = = eVisibility_NotVisible )
{
AUTO_VAR ( it , seenBy . find ( sp ) ) ;
if ( it ! = seenBy . end ( ) )
{
seenBy . erase ( it ) ;
sp - > entitiesToRemove . push_back ( e - > entityId ) ;
}
}
}
2026-03-02 15:58:20 +07:00
bool TrackedEntity : : canBySeenBy ( std : : shared_ptr < ServerPlayer > player )
2026-03-01 12:16:08 +08:00
{
// 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
// 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
// TODO - investigate further
return true ;
// return player->getLevel()->getChunkMap()->isPlayerIn(player, e->xChunk, e->zChunk);
}
2026-03-02 15:58:20 +07:00
void TrackedEntity : : updatePlayers ( EntityTracker * tracker , vector < std : : shared_ptr < Player > > * players )
2026-03-01 12:16:08 +08:00
{
for ( unsigned int i = 0 ; i < players - > size ( ) ; i + + )
{
updatePlayer ( tracker , dynamic_pointer_cast < ServerPlayer > ( players - > at ( i ) ) ) ;
}
}
2026-03-02 15:58:20 +07:00
std : : shared_ptr < Packet > TrackedEntity : : getAddEntityPacket ( )
2026-03-01 12:16:08 +08:00
{
if ( e - > removed )
{
app . DebugPrintf ( " Fetching addPacket for removed entity - %ls \n " , e - > getAName ( ) . c_str ( ) ) ;
}
// 4J-PB - replacing with a switch, rather than tons of ifs
if ( dynamic_pointer_cast < Creature > ( e ) ! = NULL )
{
yHeadRotp = Mth : : floor ( e - > getYHeadRot ( ) * 256 / 360 ) ;
2026-03-02 15:58:20 +07:00
return std : : shared_ptr < AddMobPacket > ( new AddMobPacket ( dynamic_pointer_cast < Mob > ( e ) , yRotp , xRotp , xp , yp , zp , yHeadRotp ) ) ;
2026-03-01 12:16:08 +08:00
}
switch ( e - > GetType ( ) )
{
case eTYPE_ITEMENTITY :
{
2026-03-02 15:58:20 +07:00
std : : shared_ptr < AddEntityPacket > packet = std : : shared_ptr < AddEntityPacket > ( new AddEntityPacket ( e , AddEntityPacket : : ITEM , 1 , yRotp , xRotp , xp , yp , zp ) ) ;
2026-03-01 12:16:08 +08:00
return packet ;
}
break ;
case eTYPE_SERVERPLAYER :
{
2026-03-02 15:58:20 +07:00
std : : shared_ptr < ServerPlayer > player = dynamic_pointer_cast < ServerPlayer > ( e ) ;
2026-03-01 12:16:08 +08:00
PlayerUID xuid = INVALID_XUID ;
PlayerUID OnlineXuid = INVALID_XUID ;
if ( player ! = NULL )
{
xuid = player - > getXuid ( ) ;
OnlineXuid = player - > getOnlineXuid ( ) ;
}
// 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.
2026-03-02 15:58:20 +07:00
return std : : shared_ptr < AddPlayerPacket > ( new AddPlayerPacket ( dynamic_pointer_cast < Player > ( e ) , xuid , OnlineXuid , xp , yp , zp , yRotp , xRotp , yHeadRotp ) ) ;
2026-03-01 12:16:08 +08:00
}
break ;
case eTYPE_MINECART :
{
2026-03-02 15:58:20 +07:00
std : : shared_ptr < Minecart > minecart = dynamic_pointer_cast < Minecart > ( e ) ;
if ( minecart - > type = = Minecart : : RIDEABLE ) return std : : shared_ptr < AddEntityPacket > ( new AddEntityPacket ( e , AddEntityPacket : : MINECART_RIDEABLE , yRotp , xRotp , xp , yp , zp ) ) ;
if ( minecart - > type = = Minecart : : CHEST ) return std : : shared_ptr < AddEntityPacket > ( new AddEntityPacket ( e , AddEntityPacket : : MINECART_CHEST , yRotp , xRotp , xp , yp , zp ) ) ;
if ( minecart - > type = = Minecart : : FURNACE ) return std : : shared_ptr < AddEntityPacket > ( new AddEntityPacket ( e , AddEntityPacket : : MINECART_FURNACE , yRotp , xRotp , xp , yp , zp ) ) ;
2026-03-01 12:16:08 +08:00
}
break ;
case eTYPE_BOAT :
{
2026-03-02 15:58:20 +07:00
return std : : shared_ptr < AddEntityPacket > ( new AddEntityPacket ( e , AddEntityPacket : : BOAT , yRotp , xRotp , xp , yp , zp ) ) ;
2026-03-01 12:16:08 +08:00
}
break ;
case eTYPE_ENDERDRAGON :
{
yHeadRotp = Mth : : floor ( e - > getYHeadRot ( ) * 256 / 360 ) ;
2026-03-02 15:58:20 +07:00
return std : : shared_ptr < AddMobPacket > ( new AddMobPacket ( dynamic_pointer_cast < Mob > ( e ) , yRotp , xRotp , xp , yp , zp , yHeadRotp ) ) ;
2026-03-01 12:16:08 +08:00
}
break ;
case eTYPE_FISHINGHOOK :
{
2026-03-02 15:58:20 +07:00
std : : shared_ptr < Entity > owner = dynamic_pointer_cast < FishingHook > ( e ) - > owner ;
return std : : shared_ptr < AddEntityPacket > ( new AddEntityPacket ( e , AddEntityPacket : : FISH_HOOK , owner ! = NULL ? owner - > entityId : e - > entityId , yRotp , xRotp , xp , yp , zp ) ) ;
2026-03-01 12:16:08 +08:00
}
break ;
case eTYPE_ARROW :
{
2026-03-02 15:58:20 +07:00
std : : shared_ptr < Entity > owner = ( dynamic_pointer_cast < Arrow > ( e ) ) - > owner ;
return std : : shared_ptr < AddEntityPacket > ( new AddEntityPacket ( e , AddEntityPacket : : ARROW , owner ! = NULL ? owner - > entityId : e - > entityId , yRotp , xRotp , xp , yp , zp ) ) ;
2026-03-01 12:16:08 +08:00
}
break ;
case eTYPE_SNOWBALL :
{
2026-03-02 15:58:20 +07:00
return std : : shared_ptr < AddEntityPacket > ( new AddEntityPacket ( e , AddEntityPacket : : SNOWBALL , yRotp , xRotp , xp , yp , zp ) ) ;
2026-03-01 12:16:08 +08:00
}
break ;
case eTYPE_THROWNPOTION :
{
2026-03-02 15:58:20 +07:00
return std : : shared_ptr < AddEntityPacket > ( new AddEntityPacket ( e , AddEntityPacket : : THROWN_POTION , ( ( dynamic_pointer_cast < ThrownPotion > ( e ) ) - > getPotionValue ( ) ) , yRotp , xRotp , xp , yp , zp ) ) ;
2026-03-01 12:16:08 +08:00
}
break ;
case eTYPE_THROWNEXPBOTTLE :
{
2026-03-02 15:58:20 +07:00
return std : : shared_ptr < AddEntityPacket > ( new AddEntityPacket ( e , AddEntityPacket : : THROWN_EXPBOTTLE , yRotp , xRotp , xp , yp , zp ) ) ;
2026-03-01 12:16:08 +08:00
}
break ;
case eTYPE_THROWNENDERPEARL :
{
2026-03-02 15:58:20 +07:00
return std : : shared_ptr < AddEntityPacket > ( new AddEntityPacket ( e , AddEntityPacket : : THROWN_ENDERPEARL , yRotp , xRotp , xp , yp , zp ) ) ;
2026-03-01 12:16:08 +08:00
}
break ;
case eTYPE_EYEOFENDERSIGNAL :
{
2026-03-02 15:58:20 +07:00
return std : : shared_ptr < AddEntityPacket > ( new AddEntityPacket ( e , AddEntityPacket : : EYEOFENDERSIGNAL , yRotp , xRotp , xp , yp , zp ) ) ;
2026-03-01 12:16:08 +08:00
}
break ;
case eTYPE_SMALL_FIREBALL :
{
2026-03-02 15:58:20 +07:00
std : : shared_ptr < SmallFireball > fb = dynamic_pointer_cast < SmallFireball > ( e ) ;
std : : shared_ptr < AddEntityPacket > aep = nullptr ;
2026-03-01 12:16:08 +08:00
if ( fb - > owner ! = NULL )
{
2026-03-02 15:58:20 +07:00
aep = std : : shared_ptr < AddEntityPacket > ( new AddEntityPacket ( e , AddEntityPacket : : SMALL_FIREBALL , fb - > owner - > entityId , yRotp , xRotp , xp , yp , zp ) ) ;
2026-03-01 12:16:08 +08:00
}
else
{
2026-03-02 15:58:20 +07:00
aep = std : : shared_ptr < AddEntityPacket > ( new AddEntityPacket ( e , AddEntityPacket : : SMALL_FIREBALL , 0 , yRotp , xRotp , xp , yp , zp ) ) ;
2026-03-01 12:16:08 +08:00
}
aep - > xa = ( int ) ( fb - > xPower * 8000 ) ;
aep - > ya = ( int ) ( fb - > yPower * 8000 ) ;
aep - > za = ( int ) ( fb - > zPower * 8000 ) ;
return aep ;
}
break ;
case eTYPE_DRAGON_FIREBALL :
{
2026-03-02 15:58:20 +07:00
std : : shared_ptr < DragonFireball > fb = dynamic_pointer_cast < DragonFireball > ( e ) ;
std : : shared_ptr < AddEntityPacket > aep = nullptr ;
2026-03-01 12:16:08 +08:00
if ( fb - > owner ! = NULL )
{
2026-03-02 15:58:20 +07:00
aep = std : : shared_ptr < AddEntityPacket > ( new AddEntityPacket ( e , AddEntityPacket : : DRAGON_FIRE_BALL , fb - > owner - > entityId , yRotp , xRotp , xp , yp , zp ) ) ;
2026-03-01 12:16:08 +08:00
}
else
{
2026-03-02 15:58:20 +07:00
aep = std : : shared_ptr < AddEntityPacket > ( new AddEntityPacket ( e , AddEntityPacket : : DRAGON_FIRE_BALL , 0 , yRotp , xRotp , xp , yp , zp ) ) ;
2026-03-01 12:16:08 +08:00
}
aep - > xa = ( int ) ( fb - > xPower * 8000 ) ;
aep - > ya = ( int ) ( fb - > yPower * 8000 ) ;
aep - > za = ( int ) ( fb - > zPower * 8000 ) ;
return aep ;
}
break ;
case eTYPE_FIREBALL :
{
2026-03-02 15:58:20 +07:00
std : : shared_ptr < Fireball > fb = dynamic_pointer_cast < Fireball > ( e ) ;
std : : shared_ptr < AddEntityPacket > aep = nullptr ;
2026-03-01 12:16:08 +08:00
if ( fb - > owner ! = NULL )
{
2026-03-02 15:58:20 +07:00
aep = std : : shared_ptr < AddEntityPacket > ( new AddEntityPacket ( e , AddEntityPacket : : FIREBALL , fb - > owner - > entityId , yRotp , xRotp , xp , yp , zp ) ) ;
2026-03-01 12:16:08 +08:00
}
else
{
2026-03-02 15:58:20 +07:00
aep = std : : shared_ptr < AddEntityPacket > ( new AddEntityPacket ( e , AddEntityPacket : : FIREBALL , 0 , yRotp , xRotp , xp , yp , zp ) ) ;
2026-03-01 12:16:08 +08:00
}
aep - > xa = ( int ) ( fb - > xPower * 8000 ) ;
aep - > ya = ( int ) ( fb - > yPower * 8000 ) ;
aep - > za = ( int ) ( fb - > zPower * 8000 ) ;
return aep ;
}
break ;
case eTYPE_THROWNEGG :
{
2026-03-02 15:58:20 +07:00
return std : : shared_ptr < AddEntityPacket > ( new AddEntityPacket ( e , AddEntityPacket : : EGG , yRotp , xRotp , xp , yp , zp ) ) ;
2026-03-01 12:16:08 +08:00
}
break ;
case eTYPE_PRIMEDTNT :
{
2026-03-02 15:58:20 +07:00
return std : : shared_ptr < AddEntityPacket > ( new AddEntityPacket ( e , AddEntityPacket : : PRIMED_TNT , yRotp , xRotp , xp , yp , zp ) ) ;
2026-03-01 12:16:08 +08:00
}
break ;
case eTYPE_ENDER_CRYSTAL :
{
2026-03-02 15:58:20 +07:00
return std : : shared_ptr < AddEntityPacket > ( new AddEntityPacket ( e , AddEntityPacket : : ENDER_CRYSTAL , yRotp , xRotp , xp , yp , zp ) ) ;
2026-03-01 12:16:08 +08:00
}
break ;
case eTYPE_FALLINGTILE :
{
2026-03-02 15:58:20 +07:00
std : : shared_ptr < FallingTile > ft = dynamic_pointer_cast < FallingTile > ( e ) ;
return std : : shared_ptr < AddEntityPacket > ( new AddEntityPacket ( e , AddEntityPacket : : FALLING , ft - > tile | ( ft - > data < < 16 ) , yRotp , xRotp , xp , yp , zp ) ) ;
2026-03-01 12:16:08 +08:00
}
break ;
case eTYPE_PAINTING :
{
2026-03-02 15:58:20 +07:00
return std : : shared_ptr < AddPaintingPacket > ( new AddPaintingPacket ( dynamic_pointer_cast < Painting > ( e ) ) ) ;
2026-03-01 12:16:08 +08:00
}
break ;
case eTYPE_ITEM_FRAME :
{
2026-03-02 15:58:20 +07:00
std : : shared_ptr < ItemFrame > frame = dynamic_pointer_cast < ItemFrame > ( e ) ;
2026-03-01 12:16:08 +08:00
{
int ix = ( int ) frame - > xTile ;
int iy = ( int ) frame - > yTile ;
int iz = ( int ) frame - > zTile ;
app . DebugPrintf ( " eTYPE_ITEM_FRAME xyz %d,%d,%d \n " , ix , iy , iz ) ;
}
2026-03-02 15:58:20 +07:00
std : : shared_ptr < AddEntityPacket > packet = std : : shared_ptr < AddEntityPacket > ( new AddEntityPacket ( e , AddEntityPacket : : ITEM_FRAME , frame - > dir , yRotp , xRotp , xp , yp , zp ) ) ;
2026-03-01 12:16:08 +08:00
packet - > x = Mth : : floor ( frame - > xTile * 32.0f ) ;
packet - > y = Mth : : floor ( frame - > yTile * 32.0f ) ;
packet - > z = Mth : : floor ( frame - > zTile * 32.0f ) ;
return packet ;
}
break ;
case eTYPE_EXPERIENCEORB :
{
2026-03-02 15:58:20 +07:00
return std : : shared_ptr < AddExperienceOrbPacket > ( new AddExperienceOrbPacket ( dynamic_pointer_cast < ExperienceOrb > ( e ) ) ) ;
2026-03-01 12:16:08 +08:00
}
break ;
default :
assert ( false ) ;
2026-03-02 15:58:20 +07:00
break ;
2026-03-01 12:16:08 +08:00
}
/*
if ( e - > GetType ( ) = = eTYPE_ITEMENTITY )
{
2026-03-02 15:58:20 +07:00
std : : shared_ptr < ItemEntity > itemEntity = dynamic_pointer_cast < ItemEntity > ( e ) ;
std : : shared_ptr < AddItemEntityPacket > packet = std : : shared_ptr < AddItemEntityPacket > ( new AddItemEntityPacket ( itemEntity , xp , yp , zp ) ) ;
2026-03-01 12:16:08 +08:00
itemEntity - > x = packet - > x / 32.0 ;
itemEntity - > y = packet - > y / 32.0 ;
itemEntity - > z = packet - > z / 32.0 ;
return packet ;
}
if ( e - > GetType ( ) = = eTYPE_SERVERPLAYER )
{
2026-03-02 15:58:20 +07:00
std : : shared_ptr < ServerPlayer > player = dynamic_pointer_cast < ServerPlayer > ( e ) ;
2026-03-01 12:16:08 +08:00
XUID xuid = INVALID_XUID ;
XUID OnlineXuid = INVALID_XUID ;
if ( player ! = NULL )
{
xuid = player - > getXuid ( ) ;
OnlineXuid = player - > getOnlineXuid ( ) ;
}
2026-03-02 15:58:20 +07:00
return std : : shared_ptr < AddPlayerPacket > ( new AddPlayerPacket ( dynamic_pointer_cast < Player > ( e ) , xuid , OnlineXuid , xp , yp , zp , yRotp , xRotp ) ) ;
2026-03-01 12:16:08 +08:00
}
if ( e - > GetType ( ) = = eTYPE_MINECART )
{
2026-03-02 15:58:20 +07:00
std : : shared_ptr < Minecart > minecart = dynamic_pointer_cast < Minecart > ( e ) ;
if ( minecart - > type = = Minecart : : RIDEABLE ) return std : : shared_ptr < AddEntityPacket > ( new AddEntityPacket ( e , AddEntityPacket : : MINECART_RIDEABLE , yRotp , xRotp , xp , yp , zp ) ) ;
if ( minecart - > type = = Minecart : : CHEST ) return std : : shared_ptr < AddEntityPacket > ( new AddEntityPacket ( e , AddEntityPacket : : MINECART_CHEST , yRotp , xRotp , xp , yp , zp ) ) ;
if ( minecart - > type = = Minecart : : FURNACE ) return std : : shared_ptr < AddEntityPacket > ( new AddEntityPacket ( e , AddEntityPacket : : MINECART_FURNACE , yRotp , xRotp , xp , yp , zp ) ) ;
2026-03-01 12:16:08 +08:00
}
if ( e - > GetType ( ) = = eTYPE_BOAT )
{
2026-03-02 15:58:20 +07:00
return std : : shared_ptr < AddEntityPacket > ( new AddEntityPacket ( e , AddEntityPacket : : BOAT , yRotp , xRotp , xp , yp , zp ) ) ;
2026-03-01 12:16:08 +08:00
}
if ( dynamic_pointer_cast < Creature > ( e ) ! = NULL )
{
2026-03-02 15:58:20 +07:00
return std : : shared_ptr < AddMobPacket > ( new AddMobPacket ( dynamic_pointer_cast < Mob > ( e ) , yRotp , xRotp , xp , yp , zp ) ) ;
2026-03-01 12:16:08 +08:00
}
if ( e - > GetType ( ) = = eTYPE_ENDERDRAGON )
{
2026-03-02 15:58:20 +07:00
return std : : shared_ptr < AddMobPacket > ( new AddMobPacket ( dynamic_pointer_cast < Mob > ( e ) , yRotp , xRotp , xp , yp , zp ) ) ;
2026-03-01 12:16:08 +08:00
}
if ( e - > GetType ( ) = = eTYPE_FISHINGHOOK )
{
2026-03-02 15:58:20 +07:00
std : : shared_ptr < Entity > owner = dynamic_pointer_cast < FishingHook > ( e ) - > owner ;
return std : : shared_ptr < AddEntityPacket > ( new AddEntityPacket ( e , AddEntityPacket : : FISH_HOOK , owner ! = NULL ? owner - > entityId : e - > entityId , yRotp , xRotp , xp , yp , zp ) ) ;
2026-03-01 12:16:08 +08:00
}
if ( e - > GetType ( ) = = eTYPE_ARROW )
{
2026-03-02 15:58:20 +07:00
std : : shared_ptr < Entity > owner = ( dynamic_pointer_cast < Arrow > ( e ) ) - > owner ;
return std : : shared_ptr < AddEntityPacket > ( new AddEntityPacket ( e , AddEntityPacket : : ARROW , owner ! = NULL ? owner - > entityId : e - > entityId , yRotp , xRotp , xp , yp , zp ) ) ;
2026-03-01 12:16:08 +08:00
}
if ( e - > GetType ( ) = = eTYPE_SNOWBALL )
{
2026-03-02 15:58:20 +07:00
return std : : shared_ptr < AddEntityPacket > ( new AddEntityPacket ( e , AddEntityPacket : : SNOWBALL , yRotp , xRotp , xp , yp , zp ) ) ;
2026-03-01 12:16:08 +08:00
}
if ( e - > GetType ( ) = = eTYPE_THROWNPOTION )
{
2026-03-02 15:58:20 +07:00
return std : : shared_ptr < AddEntityPacket > ( new AddEntityPacket ( e , AddEntityPacket : : THROWN_POTION , ( ( dynamic_pointer_cast < ThrownPotion > ( e ) ) - > getPotionValue ( ) ) , yRotp , xRotp , xp , yp , zp ) ) ;
2026-03-01 12:16:08 +08:00
}
if ( e - > GetType ( ) = = eTYPE_THROWNEXPBOTTLE )
{
2026-03-02 15:58:20 +07:00
return std : : shared_ptr < AddEntityPacket > ( new AddEntityPacket ( e , AddEntityPacket : : THROWN_EXPBOTTLE , yRotp , xRotp , xp , yp , zp ) ) ;
2026-03-01 12:16:08 +08:00
}
if ( e - > GetType ( ) = = eTYPE_THROWNENDERPEARL )
{
2026-03-02 15:58:20 +07:00
return std : : shared_ptr < AddEntityPacket > ( new AddEntityPacket ( e , AddEntityPacket : : THROWN_ENDERPEARL , yRotp , xRotp , xp , yp , zp ) ) ;
2026-03-01 12:16:08 +08:00
}
if ( e - > GetType ( ) = = eTYPE_EYEOFENDERSIGNAL )
{
2026-03-02 15:58:20 +07:00
return std : : shared_ptr < AddEntityPacket > ( new AddEntityPacket ( e , AddEntityPacket : : EYEOFENDERSIGNAL , yRotp , xRotp , xp , yp , zp ) ) ;
2026-03-01 12:16:08 +08:00
}
if ( e - > GetType ( ) = = eTYPE_SMALL_FIREBALL )
{
2026-03-02 15:58:20 +07:00
std : : shared_ptr < SmallFireball > fb = dynamic_pointer_cast < SmallFireball > ( e ) ;
std : : shared_ptr < AddEntityPacket > aep = NULL ;
2026-03-01 12:16:08 +08:00
if ( fb - > owner ! = NULL )
{
2026-03-02 15:58:20 +07:00
aep = std : : shared_ptr < AddEntityPacket > ( new AddEntityPacket ( e , AddEntityPacket : : SMALL_FIREBALL , fb - > owner - > entityId , yRotp , xRotp , xp , yp , zp ) ) ;
2026-03-01 12:16:08 +08:00
}
else
{
2026-03-02 15:58:20 +07:00
aep = std : : shared_ptr < AddEntityPacket > ( new AddEntityPacket ( e , AddEntityPacket : : SMALL_FIREBALL , 0 , yRotp , xRotp , xp , yp , zp ) ) ;
2026-03-01 12:16:08 +08:00
}
aep - > xa = ( int ) ( fb - > xPower * 8000 ) ;
aep - > ya = ( int ) ( fb - > yPower * 8000 ) ;
aep - > za = ( int ) ( fb - > zPower * 8000 ) ;
return aep ;
}
if ( e - > GetType ( ) = = eTYPE_FIREBALL )
{
2026-03-02 15:58:20 +07:00
std : : shared_ptr < Fireball > fb = dynamic_pointer_cast < Fireball > ( e ) ;
std : : shared_ptr < AddEntityPacket > aep = NULL ;
2026-03-01 12:16:08 +08:00
if ( fb - > owner ! = NULL )
{
2026-03-02 15:58:20 +07:00
aep = std : : shared_ptr < AddEntityPacket > ( new AddEntityPacket ( e , AddEntityPacket : : FIREBALL , fb - > owner - > entityId , yRotp , xRotp , xp , yp , zp ) ) ;
2026-03-01 12:16:08 +08:00
}
else
{
2026-03-02 15:58:20 +07:00
aep = std : : shared_ptr < AddEntityPacket > ( new AddEntityPacket ( e , AddEntityPacket : : FIREBALL , 0 , yRotp , xRotp , xp , yp , zp ) ) ;
2026-03-01 12:16:08 +08:00
}
aep - > xa = ( int ) ( fb - > xPower * 8000 ) ;
aep - > ya = ( int ) ( fb - > yPower * 8000 ) ;
aep - > za = ( int ) ( fb - > zPower * 8000 ) ;
return aep ;
}
if ( e - > GetType ( ) = = eTYPE_THROWNEGG )
{
2026-03-02 15:58:20 +07:00
return std : : shared_ptr < AddEntityPacket > ( new AddEntityPacket ( e , AddEntityPacket : : EGG , yRotp , xRotp , xp , yp , zp ) ) ;
2026-03-01 12:16:08 +08:00
}
if ( e - > GetType ( ) = = eTYPE_PRIMEDTNT )
{
2026-03-02 15:58:20 +07:00
return std : : shared_ptr < AddEntityPacket > ( new AddEntityPacket ( e , AddEntityPacket : : PRIMED_TNT , yRotp , xRotp , xp , yp , zp ) ) ;
2026-03-01 12:16:08 +08:00
}
if ( e - > GetType ( ) = = eTYPE_ENDER_CRYSTAL )
{
2026-03-02 15:58:20 +07:00
return std : : shared_ptr < AddEntityPacket > ( new AddEntityPacket ( e , AddEntityPacket : : ENDER_CRYSTAL , yRotp , xRotp , xp , yp , zp ) ) ;
2026-03-01 12:16:08 +08:00
}
if ( e - > GetType ( ) = = eTYPE_FALLINGTILE )
{
2026-03-02 15:58:20 +07:00
std : : shared_ptr < FallingTile > ft = dynamic_pointer_cast < FallingTile > ( e ) ;
if ( ft - > tile = = Tile : : sand_Id ) return std : : shared_ptr < AddEntityPacket > ( new AddEntityPacket ( e , AddEntityPacket : : FALLING_SAND , yRotp , xRotp , xp , yp , zp ) ) ;
if ( ft - > tile = = Tile : : gravel_Id ) return std : : shared_ptr < AddEntityPacket > ( new AddEntityPacket ( e , AddEntityPacket : : FALLING_GRAVEL , yRotp , xRotp , xp , yp , zp ) ) ;
if ( ft - > tile = = Tile : : dragonEgg_Id ) return std : : shared_ptr < AddEntityPacket > ( new AddEntityPacket ( e , AddEntityPacket : : FALLING_EGG , yRotp , xRotp , xp , yp , zp ) ) ;
2026-03-01 12:16:08 +08:00
}
if ( e - > GetType ( ) = = eTYPE_PAINTING )
{
2026-03-02 15:58:20 +07:00
return std : : shared_ptr < AddPaintingPacket > ( new AddPaintingPacket ( dynamic_pointer_cast < Painting > ( e ) ) ) ;
2026-03-01 12:16:08 +08:00
}
2026-03-02 15:58:20 +07:00
if ( e - > GetType ( ) = = eTYPE_ITEM_FRAME )
2026-03-01 12:16:08 +08:00
{
2026-03-02 15:58:20 +07:00
std : : shared_ptr < ItemFrame > frame = dynamic_pointer_cast < ItemFrame > ( e ) ;
2026-03-01 12:16:08 +08:00
{
int ix = ( int ) frame - > xTile ;
int iy = ( int ) frame - > yTile ;
int iz = ( int ) frame - > zTile ;
app . DebugPrintf ( " eTYPE_ITEM_FRAME xyz %d,%d,%d \n " , ix , iy , iz ) ;
}
2026-03-02 15:58:20 +07:00
std : : shared_ptr < AddEntityPacket > packet = std : : shared_ptr < AddEntityPacket > ( new AddEntityPacket ( e , AddEntityPacket : : ITEM_FRAME , frame - > dir , yRotp , xRotp , xp , yp , zp ) ) ;
2026-03-01 12:16:08 +08:00
packet - > x = Mth : : floor ( frame - > xTile * 32.0f ) ;
packet - > y = Mth : : floor ( frame - > yTile * 32.0f ) ;
packet - > z = Mth : : floor ( frame - > zTile * 32.0f ) ;
return packet ;
}
if ( e - > GetType ( ) = = eTYPE_EXPERIENCEORB )
{
2026-03-02 15:58:20 +07:00
return std : : shared_ptr < AddExperienceOrbPacket > ( new AddExperienceOrbPacket ( dynamic_pointer_cast < ExperienceOrb > ( e ) ) ) ;
2026-03-01 12:16:08 +08:00
}
assert ( false ) ;
*/
return nullptr ;
}
2026-03-02 15:58:20 +07:00
void TrackedEntity : : clear ( std : : shared_ptr < ServerPlayer > sp )
2026-03-01 12:16:08 +08:00
{
AUTO_VAR ( it , seenBy . find ( sp ) ) ;
if ( it ! = seenBy . end ( ) )
{
seenBy . erase ( it ) ;
sp - > entitiesToRemove . push_back ( e - > entityId ) ;
}
}