Оставлять EntityThrowable на поверхности

Версия Minecraft
1.7.10
1,159
38
544
Добрый день. Мне нужно чтобы EntityThrowable не падала сквозь блоки, а оставалось на них прямо как в EntityItem. Как я только не пробовал обнулять координаты и ускорение...
MyEntityThrowable:
    @Override
    public void onUpdate() {
        double[] pos = {posX, posY, posZ};
        super.onUpdate();
        if (onGround || inGround || isCollided || isCollidedHorizontally || isCollidedVertically) {
            this.motionY = 0;
            setPosition(pos[0], pos[1], pos[2]);
        }
    }

Только он все равно падает сквозь блоки.

Никак не могу понять почему onGround всегда ложный. В Entity ведь есть проверка на это дело. Мне крайне не хочется переписывать весь EntityThrowable#onUpdate() или копипастить EntityThrowable в собственный наседник Entity. Подскажите как оставлять брошеный предмет на поверхности и как сделать это наиболее красивым способом.
 
1,159
38
544

tox1cozZ

aka Agravaine
8,456
598
2,893
Долго я с этим возился и не нашел внятного решения.
Пришло делать кастомный Throwable, копируя весь обычный к себе(из-за того что не получится вызвать super.onUpdate(), ибо он вызовется тогда у дефолтного Throwable, а не у Entity).
Вот сюда пихаешь проверку, если выполняется - return.
1570697286251.png
Скину свой класс на всякий случай:
Java:
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
import net.minecraft.block.Block;
import net.minecraft.entity.Entity;
import net.minecraft.entity.IProjectile;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.util.AxisAlignedBB;
import net.minecraft.util.MovingObjectPosition;
import net.minecraft.util.Vec3;
import net.minecraft.world.World;

import java.util.List;

public abstract class EntityCustomThrowable extends Entity implements IProjectile{

    public int throwableShake;
    public Entity ignoreEntity;
    protected boolean inGround;
    protected EntityPlayer thrower;
    private int xTile = -1;
    private int yTile = -1;
    private int zTile = -1;
    private Block inTile;
    private String throwerName;
    private int ticksInGround;
    private int ticksInAir;
    private int ignoreTime;

    public EntityCustomThrowable(World worldIn){
        super(worldIn);
    }

    public EntityCustomThrowable(World worldIn, double x, double y, double z){
        this(worldIn);
        setPosition(x, y, z);
    }

    public EntityCustomThrowable(World worldIn, EntityPlayer throwerIn){
        this(worldIn, throwerIn.posX, throwerIn.posY + throwerIn.getEyeHeight() - 0.10000000149011612D, throwerIn.posZ);
        thrower = throwerIn;
    }

    @Override
    protected void entityInit(){
        setSize(0.25f, 0.25f);
        renderDistanceWeight = 10.0D;
    }

    public void throwEntity(Entity entityThrower, float rotationYawIn, float rotationPitchIn, float pitchOffset, float velocity, float inaccuracy){
        float f = -net.minecraft.util.MathHelper.sin(rotationYawIn / 180.0F * (float)Math.PI) * net.minecraft.util.MathHelper.cos(rotationPitchIn / 180.0F * (float)Math.PI);
        float f1 = net.minecraft.util.MathHelper.cos(rotationYawIn / 180.0F * (float)Math.PI) * net.minecraft.util.MathHelper.cos(rotationPitchIn / 180.0F * (float)Math.PI);
        float f2 = -net.minecraft.util.MathHelper.sin((rotationPitchIn + pitchOffset) / 180.0F * (float)Math.PI);
        setThrowableHeading(f, f2, f1, velocity, inaccuracy);
        motionX += entityThrower.motionX;
        motionZ += entityThrower.motionZ;
        if(!entityThrower.onGround){
            motionY += entityThrower.motionY;
        }
    }

    @Override
    public void setThrowableHeading(double x, double y, double z, float velocity, float inaccuracy){
        float f = (float)Math.sqrt((double)(x * x + y * y + z * z));
        x /= (double)f;
        y /= (double)f;
        z /= (double)f;
        x += rand.nextGaussian() * 0.007499999832361937 * (double)inaccuracy;
        y += rand.nextGaussian() * 0.007499999832361937 * (double)inaccuracy;
        z += rand.nextGaussian() * 0.007499999832361937 * (double)inaccuracy;
        motionX = x *= (double)velocity;
        motionY = y *= (double)velocity;
        motionZ = z *= (double)velocity;
        float f1 = (float)Math.sqrt((double)(x * x + z * z));
        rotationYaw = (float)(Math.atan2((double)x, (double)z) * 57.29577951308232);
        rotationPitch = (float)(Math.atan2((double)y, (double)f1) * 57.29577951308232);
        prevRotationYaw = rotationYaw;
        prevRotationPitch = rotationPitch;
        ticksInGround = 0;
    }

    @Override
    @SideOnly(value = Side.CLIENT)
    public void setVelocity(double x, double y, double z){
        motionX = x;
        motionY = y;
        motionZ = z;
        if(prevRotationPitch == 0.0f && prevRotationYaw == 0.0f){
            float f = (float)Math.sqrt((double)(x * x + z * z));
            rotationYaw = (float)(Math.atan2((double)x, (double)z) * 57.29577951308232);
            rotationPitch = (float)(Math.atan2((double)y, (double)f) * 57.29577951308232);
            prevRotationYaw = rotationYaw;
            prevRotationPitch = rotationPitch;
        }
    }

    @Override
    public void onUpdate(){
        lastTickPosX = posX;
        lastTickPosY = posY;
        lastTickPosZ = posZ;
        super.onUpdate();
        if(throwableShake > 0){
            --throwableShake;
        }
        if(inGround){
            if(worldObj.getBlock(xTile, yTile, zTile) == inTile){
                ++ticksInGround;
                if(ticksInGround == 1200){
                    setDead();
                }
                return;
            }
            inGround = false;
            motionX *= (double)(rand.nextFloat() * 0.2f);
            motionY *= (double)(rand.nextFloat() * 0.2f);
            motionZ *= (double)(rand.nextFloat() * 0.2f);
            ticksInGround = 0;
            ticksInAir = 0;
        }else{
            ++ticksInAir;
        }
        Vec3 posVec = Vec3.createVectorHelper(posX, posY, posZ);
        Vec3 nextPosVec = Vec3.createVectorHelper(posX + motionX, posY + motionY, posZ + motionZ);
        MovingObjectPosition rayTraceResult = worldObj.func_147447_a(posVec, nextPosVec, false, true, false);
        posVec = Vec3.createVectorHelper(posX, posY, posZ);
        nextPosVec = Vec3.createVectorHelper(posX + motionX, posY + motionY, posZ + motionZ);
        if(rayTraceResult != null){
            nextPosVec = Vec3.createVectorHelper(rayTraceResult.hitVec.xCoord, rayTraceResult.hitVec.yCoord, rayTraceResult.hitVec.zCoord);
        }
        Entity entity = null;
        List list = worldObj.getEntitiesWithinAABBExcludingEntity((Entity)this, boundingBox.expand(motionX, motionY, motionZ).expand(1.0, 1.0, 1.0));
        double distance = 0.0;
        boolean flag = false;
        for(int i = 0; i < list.size(); ++i){
            double d1;
            Entity entity1 = (Entity)list.get(i);
            if(!entity1.canBeCollidedWith()) continue;
            if(entity1 == ignoreEntity){
                flag = true;
                continue;
            }
            if(thrower != null && ticksExisted < 2 && ignoreEntity == null){
                ignoreEntity = entity1;
                flag = true;
                continue;
            }
            flag = false;
            AxisAlignedBB boundingBox = entity1.boundingBox.expand(0.3, 0.3, 0.3);
            MovingObjectPosition result = boundingBox.calculateIntercept(posVec, nextPosVec);
            if(result == null || !((d1 = posVec.squareDistanceTo(result.hitVec)) < distance) && distance != 0.0)
                continue;
            entity = entity1;
            distance = d1;
        }
        if(ignoreEntity != null){
            if(flag){
                ignoreTime = 2;
            }else if(ignoreTime-- <= 0){
                ignoreEntity = null;
            }
        }
        if(entity != null){
            rayTraceResult = new MovingObjectPosition(entity);
        }
        if(rayTraceResult != null && onImpact(rayTraceResult)){
            return;
        }
        posX += motionX;
        posY += motionY;
        posZ += motionZ;
        float f = (float)Math.sqrt((double)(motionX * motionX + motionZ * motionZ));
        rotationYaw = (float)(Math.atan2((double)motionX, (double)motionZ) * 57.29577951308232);
        rotationPitch = (float)(Math.atan2((double)motionY, (double)f) * 57.29577951308232);
        while(rotationPitch - prevRotationPitch < -180.0f){
            prevRotationPitch -= 360.0f;
        }
        while(rotationPitch - prevRotationPitch >= 180.0f){
            prevRotationPitch += 360.0f;
        }
        while(rotationYaw - prevRotationYaw < -180.0f){
            prevRotationYaw -= 360.0f;
        }
        while(rotationYaw - prevRotationYaw >= 180.0f){
            prevRotationYaw += 360.0f;
        }
        rotationPitch = prevRotationPitch + (rotationPitch - prevRotationPitch) * 0.2f;
        rotationYaw = prevRotationYaw + (rotationYaw - prevRotationYaw) * 0.2f;
        float f1 = 0.99f;
        float f2 = getGravityVelocity();
        if(isInWater()){
            for(int j = 0; j < 4; ++j){
                float f3 = 0.25f;
                worldObj.spawnParticle("bubble", posX - motionX * 0.25, posY - motionY * 0.25, posZ - motionZ * 0.25, motionX, motionY, motionZ);
            }
            f1 = 0.8f;
        }
        motionX *= (double)f1;
        motionY *= (double)f1;
        motionZ *= (double)f1;
        motionY -= (double)f2;
        setPosition(posX, posY, posZ);
    }

    protected float getGravityVelocity(){
        return 0.03f;
    }

    protected abstract boolean onImpact(MovingObjectPosition object);

    @Override
    public void writeEntityToNBT(NBTTagCompound compound){
        compound.setInteger("xTile", xTile);
        compound.setInteger("yTile", yTile);
        compound.setInteger("zTile", zTile);
        compound.setShort("inTile", (short)Block.getIdFromBlock(inTile));
        compound.setByte("shake", (byte)throwableShake);
        compound.setByte("inGround", (byte)(inGround ? 1 : 0));
        if((throwerName == null || throwerName.isEmpty()) && thrower instanceof EntityPlayer){
            throwerName = thrower.getCommandSenderName();
        }
        compound.setString("ownerName", throwerName == null ? "" : throwerName);
    }

    @Override
    public void readEntityFromNBT(NBTTagCompound compound){
        xTile = compound.getInteger("xTile");
        yTile = compound.getInteger("yTile");
        zTile = compound.getInteger("zTile");
        inTile = compound.hasKey("inTile", 8) ? Block.getBlockFromName((String)compound.getString("inTile")) : Block.getBlockById((int)(compound.getByte("inTile") & 255));
        throwableShake = compound.getByte("shake") & 255;
        inGround = compound.getByte("inGround") == 1;
        thrower = null;
        throwerName = compound.getString("ownerName");
        if(throwerName.isEmpty()){
            throwerName = null;
        }
        thrower = getThrower();
    }

    public EntityPlayer getThrower(){
        if(thrower == null && throwerName != null && !throwerName.isEmpty()){
            thrower = worldObj.getPlayerEntityByName(throwerName);
        }
        return thrower;
    }

    public double getMotionSpeed(){
        return Math.sqrt(Math.pow(motionX, 2.0) + Math.pow(motionY, 2.0) + Math.pow(motionZ, 2.0));
    }
}
 
1,159
38
544
@Agravaine это же жопа полная. Очень не хочется верить что это единственный возможный вариант.

Вот еще вопросец. Такие флаги как onGround, isCollidedHorizontally, isCollidedVertically, isCollided обновляются при вызове Entity#moveEntity() из onUpdate. Все нормальные ентити юзают moveEntity() чтобы применить ускорение к координатам, но только не EntityThrowable. Почему?
 

tox1cozZ

aka Agravaine
8,456
598
2,893
это же жопа полная
Мне норм, ибо нужна полная свобода действий в своём энтити. Создал свой класс и наследуешься от него, какая разница?)

Все нормальные ентити юзают moveEntity() чтобы применить ускорение к координатам, но только не EntityThrowable
Видать не было необходимости. У стрел полностью свой апдейт, снежки при столкновении умирают сразу, то есть лежать они на полу не могут. moveEntity по идее тяжелее чем такое. Зачем тратить лишние ресурсы на просчет этих значений?
 
Сверху