2026-03-01 12:16:08 +08:00
# include "stdafx.h"
# include "net.minecraft.world.phys.h"
# include "net.minecraft.world.entity.h"
# include "net.minecraft.world.level.tile.h"
# include "net.minecraft.world.level.h"
# include "net.minecraft.world.damagesource.h"
# include "com.mojang.nbt.h"
# include "HangingEntity.h"
void HangingEntity : : _init ( Level * level )
2026-03-06 02:11:18 +07:00
{
2026-03-01 12:16:08 +08:00
checkInterval = 0 ;
dir = 0 ;
xTile = yTile = zTile = 0 ;
2026-03-03 03:04:10 +08:00
this - > heightOffset = 0 ;
this - > setSize ( 0.5f , 0.5f ) ;
2026-03-01 12:16:08 +08:00
}
HangingEntity : : HangingEntity ( Level * level ) : Entity ( level )
{
_init ( level ) ;
}
HangingEntity : : HangingEntity ( Level * level , int xTile , int yTile , int zTile , int dir ) : Entity ( level )
{
_init ( level ) ;
this - > xTile = xTile ;
this - > yTile = yTile ;
this - > zTile = zTile ;
}
2026-03-06 02:11:18 +07:00
void HangingEntity : : setDir ( int dir )
2026-03-01 12:16:08 +08:00
{
this - > dir = dir ;
2026-03-08 19:08:36 -04:00
yRotO = yRot = static_cast < float > ( dir * 90 ) ;
2026-03-01 12:16:08 +08:00
2026-03-08 19:08:36 -04:00
float w = static_cast < float > ( getWidth ( ) ) ;
float h = static_cast < float > ( getHeight ( ) ) ;
float d = static_cast < float > ( getWidth ( ) ) ;
2026-03-01 12:16:08 +08:00
2026-03-06 02:11:18 +07:00
if ( dir = = Direction : : NORTH | | dir = = Direction : : SOUTH )
2026-03-01 12:16:08 +08:00
{
d = 0.5f ;
2026-03-08 19:08:36 -04:00
yRot = yRotO = static_cast < float > ( Direction : : DIRECTION_OPPOSITE [ dir ] * 90 ) ;
2026-03-06 02:11:18 +07:00
}
else
2026-03-01 12:16:08 +08:00
{
w = 0.5f ;
}
w / = 32.0f ;
h / = 32.0f ;
d / = 32.0f ;
float x = xTile + 0.5f ;
float y = yTile + 0.5f ;
float z = zTile + 0.5f ;
2026-03-09 13:21:22 +01:00
float originalX = x ;
float originalZ = z ;
2026-03-01 12:16:08 +08:00
float fOffs = 0.5f + 1.0f / 16.0f ;
2026-03-06 12:06:19 +01:00
if ( this - > GetType ( ) = = eTYPE_PAINTING )
{
fOffs = 0.5f + 1.0f / 32.0f ; //dividing by 16.0f introduce a small gap between the block and the painting. See https://github.com/smartcmd/MinecraftConsoles/issues/661
}
2026-03-01 12:16:08 +08:00
if ( dir = = Direction : : NORTH ) z - = fOffs ;
if ( dir = = Direction : : WEST ) x - = fOffs ;
if ( dir = = Direction : : SOUTH ) z + = fOffs ;
if ( dir = = Direction : : EAST ) x + = fOffs ;
if ( dir = = Direction : : NORTH ) x - = offs ( getWidth ( ) ) ;
if ( dir = = Direction : : WEST ) z + = offs ( getWidth ( ) ) ;
if ( dir = = Direction : : SOUTH ) x + = offs ( getWidth ( ) ) ;
if ( dir = = Direction : : EAST ) z - = offs ( getWidth ( ) ) ;
y + = offs ( getHeight ( ) ) ;
2026-03-03 03:04:10 +08:00
setPos ( x , y , z ) ;
2026-03-01 12:16:08 +08:00
float ss = - ( 0.5f / 16.0f ) ;
2026-03-09 13:21:22 +01:00
//dividing the fOffs by 32 breaks the BB and allow paintings to be placed on a block when they shouldn't
//so we need to modify the x and z to set their value as if the fOffs was divided by 16 and not 32
if ( this - > GetType ( ) = = eTYPE_PAINTING )
{
fOffs = 0.5f + 1.0f / 16.0f ;
if ( dir = = Direction : : NORTH ) originalZ - = fOffs ;
if ( dir = = Direction : : WEST ) originalX - = fOffs ;
if ( dir = = Direction : : SOUTH ) originalZ + = fOffs ;
if ( dir = = Direction : : EAST ) originalX + = fOffs ;
if ( dir = = Direction : : NORTH ) originalX - = offs ( getWidth ( ) ) ;
if ( dir = = Direction : : WEST ) originalZ + = offs ( getWidth ( ) ) ;
if ( dir = = Direction : : SOUTH ) originalX + = offs ( getWidth ( ) ) ;
if ( dir = = Direction : : EAST ) originalZ - = offs ( getWidth ( ) ) ;
x = originalX ;
z = originalZ ;
}
2026-03-01 12:16:08 +08:00
// 4J Stu - Due to rotations the bb couold be set with a lower bound x/z being higher than the higher bound
float x0 = x - w - ss ;
float x1 = x + w + ss ;
float y0 = y - h - ss ;
float y1 = y + h + ss ;
float z0 = z - d - ss ;
float z1 = z + d + ss ;
bb - > set ( min ( x0 , x1 ) , min ( y0 , y1 ) , min ( z0 , z1 ) , max ( x0 , x1 ) , max ( y0 , y1 ) , max ( z0 , z1 ) ) ;
}
2026-03-06 02:11:18 +07:00
float HangingEntity : : offs ( int w )
2026-03-01 12:16:08 +08:00
{
if ( w = = 32 ) return 0.5f ;
if ( w = = 64 ) return 0.5f ;
return 0.0f ;
}
2026-03-06 02:11:18 +07:00
void HangingEntity : : tick ( )
2026-03-01 12:16:08 +08:00
{
2026-03-03 03:04:10 +08:00
xo = x ;
yo = y ;
zo = z ;
if ( checkInterval + + = = 20 * 5 & & ! level - > isClientSide )
2026-03-01 12:16:08 +08:00
{
checkInterval = 0 ;
2026-03-06 02:11:18 +07:00
if ( ! removed & & ! survives ( ) )
2026-03-01 12:16:08 +08:00
{
remove ( ) ;
2026-03-03 03:04:10 +08:00
dropItem ( nullptr ) ;
2026-03-01 12:16:08 +08:00
}
}
}
2026-03-06 02:11:18 +07:00
bool HangingEntity : : survives ( )
2026-03-01 12:16:08 +08:00
{
2026-03-06 02:11:18 +07:00
if ( level - > getCubes ( shared_from_this ( ) , bb ) - > size ( ) ! = 0 ) //isEmpty())
2026-03-01 12:16:08 +08:00
{
return false ;
2026-03-06 02:11:18 +07:00
}
else
2026-03-01 12:16:08 +08:00
{
int ws = max ( 1 , getWidth ( ) / 16 ) ;
int hs = max ( 1 , getHeight ( ) / 16 ) ;
int xt = xTile ;
int yt = yTile ;
int zt = zTile ;
if ( dir = = Direction : : NORTH ) xt = Mth : : floor ( x - getWidth ( ) / 32.0f ) ;
if ( dir = = Direction : : WEST ) zt = Mth : : floor ( z - getWidth ( ) / 32.0f ) ;
if ( dir = = Direction : : SOUTH ) xt = Mth : : floor ( x - getWidth ( ) / 32.0f ) ;
if ( dir = = Direction : : EAST ) zt = Mth : : floor ( z - getWidth ( ) / 32.0f ) ;
yt = Mth : : floor ( y - getHeight ( ) / 32.0f ) ;
for ( int ss = 0 ; ss < ws ; ss + + )
{
2026-03-06 02:11:18 +07:00
for ( int yy = 0 ; yy < hs ; yy + + )
2026-03-01 12:16:08 +08:00
{
Material * m ;
2026-03-06 02:11:18 +07:00
if ( dir = = Direction : : NORTH | | dir = = Direction : : SOUTH )
2026-03-01 12:16:08 +08:00
{
m = level - > getMaterial ( xt + ss , yt + yy , zTile ) ;
2026-03-06 02:11:18 +07:00
}
else
2026-03-01 12:16:08 +08:00
{
m = level - > getMaterial ( xTile , yt + yy , zt + ss ) ;
}
2026-03-06 02:11:18 +07:00
if ( ! m - > isSolid ( ) )
2026-03-01 12:16:08 +08:00
{
return false ;
}
}
2026-03-02 17:37:16 +07:00
vector < shared_ptr < Entity > > * entities = level - > getEntities ( shared_from_this ( ) , bb ) ;
2026-03-01 12:16:08 +08:00
2026-03-08 19:08:36 -04:00
if ( entities ! = nullptr & & entities - > size ( ) > 0 )
2026-03-01 12:16:08 +08:00
{
2026-03-06 02:11:18 +07:00
for ( auto & e : * entities )
2026-03-01 12:16:08 +08:00
{
2026-03-06 02:11:18 +07:00
if ( e & & e - > instanceof ( eTYPE_HANGING_ENTITY ) )
2026-03-01 12:16:08 +08:00
{
return false ;
}
}
}
}
}
return true ;
}
2026-03-06 02:11:18 +07:00
bool HangingEntity : : isPickable ( )
2026-03-01 12:16:08 +08:00
{
return true ;
}
2026-03-06 02:11:18 +07:00
bool HangingEntity : : skipAttackInteraction ( shared_ptr < Entity > source )
2026-03-01 12:16:08 +08:00
{
if ( source - > GetType ( ) = = eTYPE_PLAYER )
{
2026-03-02 17:36:56 +07:00
return hurt ( DamageSource : : playerAttack ( dynamic_pointer_cast < Player > ( source ) ) , 0 ) ;
2026-03-01 12:16:08 +08:00
}
return false ;
}
2026-03-06 02:11:18 +07:00
bool HangingEntity : : hurt ( DamageSource * source , float damage )
2026-03-01 12:16:08 +08:00
{
2026-03-03 03:04:10 +08:00
if ( isInvulnerable ( ) ) return false ;
2026-03-06 02:11:18 +07:00
if ( ! removed & & ! level - > isClientSide )
2026-03-01 12:16:08 +08:00
{
2026-03-08 19:08:36 -04:00
if ( dynamic_cast < EntityDamageSource * > ( source ) ! = nullptr )
2026-03-01 12:16:08 +08:00
{
2026-03-02 17:37:16 +07:00
shared_ptr < Entity > sourceEntity = source - > getDirectEntity ( ) ;
2026-03-01 12:16:08 +08:00
2026-03-08 19:08:36 -04:00
if ( ( sourceEntity ! = nullptr ) & & sourceEntity - > instanceof ( eTYPE_PLAYER ) & & ! dynamic_pointer_cast < Player > ( sourceEntity ) - > isAllowedToHurtEntity ( shared_from_this ( ) ) )
2026-03-01 12:16:08 +08:00
{
return false ;
}
}
remove ( ) ;
markHurt ( ) ;
2026-03-02 17:37:16 +07:00
shared_ptr < Player > player = nullptr ;
shared_ptr < Entity > e = source - > getEntity ( ) ;
2026-03-08 19:08:36 -04:00
if ( ( e ! = nullptr ) & & e - > instanceof ( eTYPE_PLAYER ) ) // check if it's serverplayer or player
2026-03-01 12:16:08 +08:00
{
2026-03-02 17:36:56 +07:00
player = dynamic_pointer_cast < Player > ( e ) ;
2026-03-01 12:16:08 +08:00
}
2026-03-08 19:08:36 -04:00
if ( player ! = nullptr & & player - > abilities . instabuild )
2026-03-01 12:16:08 +08:00
{
return true ;
}
2026-03-03 03:04:10 +08:00
dropItem ( nullptr ) ;
2026-03-01 12:16:08 +08:00
}
return true ;
}
// 4J - added noEntityCubes parameter
2026-03-06 02:11:18 +07:00
void HangingEntity : : move ( double xa , double ya , double za , bool noEntityCubes )
2026-03-01 12:16:08 +08:00
{
2026-03-06 02:11:18 +07:00
if ( ! level - > isClientSide & & ! removed & & ( xa * xa + ya * ya + za * za ) > 0 )
2026-03-01 12:16:08 +08:00
{
remove ( ) ;
2026-03-03 03:04:10 +08:00
dropItem ( nullptr ) ;
2026-03-01 12:16:08 +08:00
}
}
2026-03-06 02:11:18 +07:00
void HangingEntity : : push ( double xa , double ya , double za )
2026-03-01 12:16:08 +08:00
{
2026-03-06 02:11:18 +07:00
if ( ! level - > isClientSide & & ! removed & & ( xa * xa + ya * ya + za * za ) > 0 )
2026-03-01 12:16:08 +08:00
{
remove ( ) ;
2026-03-03 03:04:10 +08:00
dropItem ( nullptr ) ;
2026-03-01 12:16:08 +08:00
}
}
2026-03-06 02:11:18 +07:00
void HangingEntity : : addAdditonalSaveData ( CompoundTag * tag )
2026-03-01 12:16:08 +08:00
{
2026-03-08 19:08:36 -04:00
tag - > putByte ( L " Direction " , static_cast < byte > ( dir ) ) ;
2026-03-01 12:16:08 +08:00
tag - > putInt ( L " TileX " , xTile ) ;
tag - > putInt ( L " TileY " , yTile ) ;
tag - > putInt ( L " TileZ " , zTile ) ;
// Back compat
2026-03-06 02:11:18 +07:00
switch ( dir )
2026-03-01 12:16:08 +08:00
{
case Direction : : NORTH :
tag - > putByte ( L " Dir " , ( byte ) 0 ) ;
break ;
case Direction : : WEST :
tag - > putByte ( L " Dir " , ( byte ) 1 ) ;
break ;
case Direction : : SOUTH :
tag - > putByte ( L " Dir " , ( byte ) 2 ) ;
break ;
case Direction : : EAST :
tag - > putByte ( L " Dir " , ( byte ) 3 ) ;
break ;
}
}
2026-03-06 02:11:18 +07:00
void HangingEntity : : readAdditionalSaveData ( CompoundTag * tag )
2026-03-01 12:16:08 +08:00
{
2026-03-06 02:11:18 +07:00
if ( tag - > contains ( L " Direction " ) )
2026-03-01 12:16:08 +08:00
{
dir = tag - > getByte ( L " Direction " ) ;
2026-03-06 02:11:18 +07:00
}
else
2026-03-01 12:16:08 +08:00
{
2026-03-06 02:11:18 +07:00
switch ( tag - > getByte ( L " Dir " ) )
2026-03-01 12:16:08 +08:00
{
case 0 :
dir = Direction : : NORTH ;
break ;
case 1 :
dir = Direction : : WEST ;
break ;
case 2 :
dir = Direction : : SOUTH ;
break ;
case 3 :
dir = Direction : : EAST ;
break ;
}
}
xTile = tag - > getInt ( L " TileX " ) ;
yTile = tag - > getInt ( L " TileY " ) ;
zTile = tag - > getInt ( L " TileZ " ) ;
setDir ( dir ) ;
}
2026-03-03 03:04:10 +08:00
bool HangingEntity : : repositionEntityAfterLoad ( )
{
return false ;
}