package net.minecraft.world.entity.vehicle;

import net.minecraft.Util;
import com.google.common.collect.Maps;
import net.minecraft.network.syncher.SynchedEntityData;
import net.minecraft.network.syncher.EntityDataSerializers;
import java.util.EnumMap;
import net.minecraft.network.protocol.game.ClientboundAddEntityPacket;
import net.minecraft.network.protocol.Packet;
import net.minecraft.nbt.Tag;
import net.minecraft.nbt.NbtUtils;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.block.BaseRailBlock;
import net.minecraft.world.entity.MoverType;
import java.util.Iterator;
import java.util.List;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.entity.animal.IronGolem;
import java.util.function.Predicate;
import net.minecraft.world.entity.EntitySelector;
import net.minecraft.world.level.block.state.properties.Property;
import net.minecraft.world.level.block.PoweredRailBlock;
import net.minecraft.tags.BlockTags;
import net.minecraft.core.BlockPos;
import net.minecraft.util.Mth;
import net.minecraft.core.Direction;
import net.minecraft.world.level.ItemLike;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.Items;
import net.minecraft.world.level.GameRules;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.damagesource.DamageSource;
import javax.annotation.Nullable;
import net.minecraft.world.phys.AABB;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.phys.Vec3;
import net.minecraft.world.level.Level;
import net.minecraft.world.entity.EntityType;
import net.minecraft.core.Vec3i;
import com.mojang.datafixers.util.Pair;
import net.minecraft.world.level.block.state.properties.RailShape;
import java.util.Map;
import net.minecraft.network.syncher.EntityDataAccessor;
import net.minecraft.world.entity.Entity;

public abstract class AbstractMinecart extends Entity {
    private static final EntityDataAccessor<Integer> DATA_ID_HURT;
    private static final EntityDataAccessor<Integer> DATA_ID_HURTDIR;
    private static final EntityDataAccessor<Float> DATA_ID_DAMAGE;
    private static final EntityDataAccessor<Integer> DATA_ID_DISPLAY_BLOCK;
    private static final EntityDataAccessor<Integer> DATA_ID_DISPLAY_OFFSET;
    private static final EntityDataAccessor<Boolean> DATA_ID_CUSTOM_DISPLAY;
    private boolean flipped;
    private static final Map<RailShape, Pair<Vec3i, Vec3i>> EXITS;
    private int lSteps;
    private double lx;
    private double ly;
    private double lz;
    private double lyr;
    private double lxr;
    private double lxd;
    private double lyd;
    private double lzd;
    
    protected AbstractMinecart(final EntityType<?> aku, final Level bjw) {
        super(aku, bjw);
        this.blocksBuilding = true;
    }
    
    protected AbstractMinecart(final EntityType<?> aku, final Level bjw, final double double3, final double double4, final double double5) {
        this(aku, bjw);
        this.setPos(double3, double4, double5);
        this.setDeltaMovement(Vec3.ZERO);
        this.xo = double3;
        this.yo = double4;
        this.zo = double5;
    }
    
    public static AbstractMinecart createMinecart(final Level bjw, final double double2, final double double3, final double double4, final Type a) {
        if (a == Type.CHEST) {
            return new MinecartChest(bjw, double2, double3, double4);
        }
        if (a == Type.FURNACE) {
            return new MinecartFurnace(bjw, double2, double3, double4);
        }
        if (a == Type.TNT) {
            return new MinecartTNT(bjw, double2, double3, double4);
        }
        if (a == Type.SPAWNER) {
            return new MinecartSpawner(bjw, double2, double3, double4);
        }
        if (a == Type.HOPPER) {
            return new MinecartHopper(bjw, double2, double3, double4);
        }
        if (a == Type.COMMAND_BLOCK) {
            return new MinecartCommandBlock(bjw, double2, double3, double4);
        }
        return new Minecart(bjw, double2, double3, double4);
    }
    
    @Override
    protected boolean isMovementNoisy() {
        return false;
    }
    
    @Override
    protected void defineSynchedData() {
        this.entityData.<Integer>define(AbstractMinecart.DATA_ID_HURT, 0);
        this.entityData.<Integer>define(AbstractMinecart.DATA_ID_HURTDIR, 1);
        this.entityData.<Float>define(AbstractMinecart.DATA_ID_DAMAGE, 0.0f);
        this.entityData.<Integer>define(AbstractMinecart.DATA_ID_DISPLAY_BLOCK, Block.getId(Blocks.AIR.defaultBlockState()));
        this.entityData.<Integer>define(AbstractMinecart.DATA_ID_DISPLAY_OFFSET, 6);
        this.entityData.<Boolean>define(AbstractMinecart.DATA_ID_CUSTOM_DISPLAY, false);
    }
    
    @Nullable
    @Override
    public AABB getCollideAgainstBox(final Entity akq) {
        if (akq.isPushable()) {
            return akq.getBoundingBox();
        }
        return null;
    }
    
    @Override
    public boolean isPushable() {
        return true;
    }
    
    @Override
    public double getRideHeight() {
        return 0.0;
    }
    
    @Override
    public boolean hurt(final DamageSource ajz, final float float2) {
        if (this.level.isClientSide || this.removed) {
            return true;
        }
        if (this.isInvulnerableTo(ajz)) {
            return false;
        }
        this.setHurtDir(-this.getHurtDir());
        this.setHurtTime(10);
        this.markHurt();
        this.setDamage(this.getDamage() + float2 * 10.0f);
        final boolean boolean4 = ajz.getEntity() instanceof Player && ((Player)ajz.getEntity()).abilities.instabuild;
        if (boolean4 || this.getDamage() > 40.0f) {
            this.ejectPassengers();
            if (!boolean4 || this.hasCustomName()) {
                this.destroy(ajz);
            }
            else {
                this.remove();
            }
        }
        return true;
    }
    
    public void destroy(final DamageSource ajz) {
        this.remove();
        if (this.level.getGameRules().getBoolean(GameRules.RULE_DOENTITYDROPS)) {
            final ItemStack ben3 = new ItemStack(Items.MINECART);
            if (this.hasCustomName()) {
                ben3.setHoverName(this.getCustomName());
            }
            this.spawnAtLocation(ben3);
        }
    }
    
    @Override
    public void animateHurt() {
        this.setHurtDir(-this.getHurtDir());
        this.setHurtTime(10);
        this.setDamage(this.getDamage() + this.getDamage() * 10.0f);
    }
    
    @Override
    public boolean isPickable() {
        return !this.removed;
    }
    
    private static Pair<Vec3i, Vec3i> exits(final RailShape bzn) {
        return AbstractMinecart.EXITS.get(bzn);
    }
    
    @Override
    public Direction getMotionDirection() {
        return this.flipped ? this.getDirection().getOpposite().getClockWise() : this.getDirection().getClockWise();
    }
    
    @Override
    public void tick() {
        if (this.getHurtTime() > 0) {
            this.setHurtTime(this.getHurtTime() - 1);
        }
        if (this.getDamage() > 0.0f) {
            this.setDamage(this.getDamage() - 1.0f);
        }
        if (this.getY() < -64.0) {
            this.outOfWorld();
        }
        this.handleNetherPortal();
        if (this.level.isClientSide) {
            if (this.lSteps > 0) {
                final double double2 = this.getX() + (this.lx - this.getX()) / this.lSteps;
                final double double3 = this.getY() + (this.ly - this.getY()) / this.lSteps;
                final double double4 = this.getZ() + (this.lz - this.getZ()) / this.lSteps;
                final double double5 = Mth.wrapDegrees(this.lyr - this.yRot);
                this.yRot += (float)(double5 / this.lSteps);
                this.xRot += (float)((this.lxr - this.xRot) / this.lSteps);
                --this.lSteps;
                this.setPos(double2, double3, double4);
                this.setRot(this.yRot, this.xRot);
            }
            else {
                this.reapplyPosition();
                this.setRot(this.yRot, this.xRot);
            }
            return;
        }
        if (!this.isNoGravity()) {
            this.setDeltaMovement(this.getDeltaMovement().add(0.0, -0.04, 0.0));
        }
        final int integer2 = Mth.floor(this.getX());
        int integer3 = Mth.floor(this.getY());
        final int integer4 = Mth.floor(this.getZ());
        if (this.level.getBlockState(new BlockPos(integer2, integer3 - 1, integer4)).is(BlockTags.RAILS)) {
            --integer3;
        }
        final BlockPos fk5 = new BlockPos(integer2, integer3, integer4);
        final BlockState byj6 = this.level.getBlockState(fk5);
        if (byj6.is(BlockTags.RAILS)) {
            this.moveAlongTrack(fk5, byj6);
            if (byj6.getBlock() == Blocks.ACTIVATOR_RAIL) {
                this.activateMinecart(integer2, integer3, integer4, byj6.<Boolean>getValue((Property<Boolean>)PoweredRailBlock.POWERED));
            }
        }
        else {
            this.comeOffTrack();
        }
        this.checkInsideBlocks();
        this.xRot = 0.0f;
        final double double6 = this.xo - this.getX();
        final double double7 = this.zo - this.getZ();
        if (double6 * double6 + double7 * double7 > 0.001) {
            this.yRot = (float)(Mth.atan2(double7, double6) * 180.0 / 3.141592653589793);
            if (this.flipped) {
                this.yRot += 180.0f;
            }
        }
        final double double8 = Mth.wrapDegrees(this.yRot - this.yRotO);
        if (double8 < -170.0 || double8 >= 170.0) {
            this.yRot += 180.0f;
            this.flipped = !this.flipped;
        }
        this.setRot(this.yRot, this.xRot);
        if (this.getMinecartType() == Type.RIDEABLE && Entity.getHorizontalDistanceSqr(this.getDeltaMovement()) > 0.01) {
            final List<Entity> list13 = this.level.getEntities(this, this.getBoundingBox().inflate(0.20000000298023224, 0.0, 0.20000000298023224), EntitySelector.pushableBy(this));
            if (!list13.isEmpty()) {
                for (int integer5 = 0; integer5 < list13.size(); ++integer5) {
                    final Entity akq15 = list13.get(integer5);
                    if (akq15 instanceof Player || akq15 instanceof IronGolem || akq15 instanceof AbstractMinecart || this.isVehicle() || akq15.isPassenger()) {
                        akq15.push(this);
                    }
                    else {
                        akq15.startRiding(this);
                    }
                }
            }
        }
        else {
            for (final Entity akq16 : this.level.getEntities(this, this.getBoundingBox().inflate(0.20000000298023224, 0.0, 0.20000000298023224))) {
                if (!this.hasPassenger(akq16) && akq16.isPushable() && akq16 instanceof AbstractMinecart) {
                    akq16.push(this);
                }
            }
        }
        this.updateInWaterState();
    }
    
    protected double getMaxSpeed() {
        return 0.4;
    }
    
    public void activateMinecart(final int integer1, final int integer2, final int integer3, final boolean boolean4) {
    }
    
    protected void comeOffTrack() {
        final double double2 = this.getMaxSpeed();
        final Vec3 cvl4 = this.getDeltaMovement();
        this.setDeltaMovement(Mth.clamp(cvl4.x, -double2, double2), cvl4.y, Mth.clamp(cvl4.z, -double2, double2));
        if (this.onGround) {
            this.setDeltaMovement(this.getDeltaMovement().scale(0.5));
        }
        this.move(MoverType.SELF, this.getDeltaMovement());
        if (!this.onGround) {
            this.setDeltaMovement(this.getDeltaMovement().scale(0.95));
        }
    }
    
    protected void moveAlongTrack(final BlockPos fk, final BlockState byj) {
        this.fallDistance = 0.0f;
        double double4 = this.getX();
        double double5 = this.getY();
        double double6 = this.getZ();
        final Vec3 cvl10 = this.getPos(double4, double5, double6);
        double5 = fk.getY();
        boolean boolean11 = false;
        boolean boolean12 = false;
        final BaseRailBlock boy13 = (BaseRailBlock)byj.getBlock();
        if (boy13 == Blocks.POWERED_RAIL) {
            boolean11 = byj.<Boolean>getValue((Property<Boolean>)PoweredRailBlock.POWERED);
            boolean12 = !boolean11;
        }
        final double double7 = 0.0078125;
        Vec3 cvl11 = this.getDeltaMovement();
        final RailShape bzn17 = byj.<RailShape>getValue(boy13.getShapeProperty());
        switch (bzn17) {
            case ASCENDING_EAST: {
                this.setDeltaMovement(cvl11.add(-0.0078125, 0.0, 0.0));
                ++double5;
                break;
            }
            case ASCENDING_WEST: {
                this.setDeltaMovement(cvl11.add(0.0078125, 0.0, 0.0));
                ++double5;
                break;
            }
            case ASCENDING_NORTH: {
                this.setDeltaMovement(cvl11.add(0.0, 0.0, 0.0078125));
                ++double5;
                break;
            }
            case ASCENDING_SOUTH: {
                this.setDeltaMovement(cvl11.add(0.0, 0.0, -0.0078125));
                ++double5;
                break;
            }
        }
        cvl11 = this.getDeltaMovement();
        final Pair<Vec3i, Vec3i> pair18 = exits(bzn17);
        final Vec3i gg19 = (Vec3i)pair18.getFirst();
        final Vec3i gg20 = (Vec3i)pair18.getSecond();
        double double8 = gg20.getX() - gg19.getX();
        double double9 = gg20.getZ() - gg19.getZ();
        final double double10 = Math.sqrt(double8 * double8 + double9 * double9);
        final double double11 = cvl11.x * double8 + cvl11.z * double9;
        if (double11 < 0.0) {
            double8 = -double8;
            double9 = -double9;
        }
        final double double12 = Math.min(2.0, Math.sqrt(Entity.getHorizontalDistanceSqr(cvl11)));
        cvl11 = new Vec3(double12 * double8 / double10, cvl11.y, double12 * double9 / double10);
        this.setDeltaMovement(cvl11);
        final Entity akq31 = this.getPassengers().isEmpty() ? null : this.getPassengers().get(0);
        if (akq31 instanceof Player) {
            final Vec3 cvl12 = akq31.getDeltaMovement();
            final double double13 = Entity.getHorizontalDistanceSqr(cvl12);
            final double double14 = Entity.getHorizontalDistanceSqr(this.getDeltaMovement());
            if (double13 > 1.0E-4 && double14 < 0.01) {
                this.setDeltaMovement(this.getDeltaMovement().add(cvl12.x * 0.1, 0.0, cvl12.z * 0.1));
                boolean12 = false;
            }
        }
        if (boolean12) {
            final double double15 = Math.sqrt(Entity.getHorizontalDistanceSqr(this.getDeltaMovement()));
            if (double15 < 0.03) {
                this.setDeltaMovement(Vec3.ZERO);
            }
            else {
                this.setDeltaMovement(this.getDeltaMovement().multiply(0.5, 0.0, 0.5));
            }
        }
        final double double15 = fk.getX() + 0.5 + gg19.getX() * 0.5;
        final double double16 = fk.getZ() + 0.5 + gg19.getZ() * 0.5;
        final double double17 = fk.getX() + 0.5 + gg20.getX() * 0.5;
        final double double18 = fk.getZ() + 0.5 + gg20.getZ() * 0.5;
        double8 = double17 - double15;
        double9 = double18 - double16;
        double double19;
        if (double8 == 0.0) {
            double19 = double6 - fk.getZ();
        }
        else if (double9 == 0.0) {
            double19 = double4 - fk.getX();
        }
        else {
            final double double20 = double4 - double15;
            final double double21 = double6 - double16;
            double19 = (double20 * double8 + double21 * double9) * 2.0;
        }
        double4 = double15 + double8 * double19;
        double6 = double16 + double9 * double19;
        this.setPos(double4, double5, double6);
        final double double20 = this.isVehicle() ? 0.75 : 1.0;
        final double double21 = this.getMaxSpeed();
        cvl11 = this.getDeltaMovement();
        this.move(MoverType.SELF, new Vec3(Mth.clamp(double20 * cvl11.x, -double21, double21), 0.0, Mth.clamp(double20 * cvl11.z, -double21, double21)));
        if (gg19.getY() != 0 && Mth.floor(this.getX()) - fk.getX() == gg19.getX() && Mth.floor(this.getZ()) - fk.getZ() == gg19.getZ()) {
            this.setPos(this.getX(), this.getY() + gg19.getY(), this.getZ());
        }
        else if (gg20.getY() != 0 && Mth.floor(this.getX()) - fk.getX() == gg20.getX() && Mth.floor(this.getZ()) - fk.getZ() == gg20.getZ()) {
            this.setPos(this.getX(), this.getY() + gg20.getY(), this.getZ());
        }
        this.applyNaturalSlowdown();
        final Vec3 cvl13 = this.getPos(this.getX(), this.getY(), this.getZ());
        if (cvl13 != null && cvl10 != null) {
            final double double22 = (cvl10.y - cvl13.y) * 0.05;
            final Vec3 cvl14 = this.getDeltaMovement();
            final double double23 = Math.sqrt(Entity.getHorizontalDistanceSqr(cvl14));
            if (double23 > 0.0) {
                this.setDeltaMovement(cvl14.multiply((double23 + double22) / double23, 1.0, (double23 + double22) / double23));
            }
            this.setPos(this.getX(), cvl13.y, this.getZ());
        }
        final int integer47 = Mth.floor(this.getX());
        final int integer48 = Mth.floor(this.getZ());
        if (integer47 != fk.getX() || integer48 != fk.getZ()) {
            final Vec3 cvl14 = this.getDeltaMovement();
            final double double23 = Math.sqrt(Entity.getHorizontalDistanceSqr(cvl14));
            this.setDeltaMovement(double23 * (integer47 - fk.getX()), cvl14.y, double23 * (integer48 - fk.getZ()));
        }
        if (boolean11) {
            final Vec3 cvl14 = this.getDeltaMovement();
            final double double23 = Math.sqrt(Entity.getHorizontalDistanceSqr(cvl14));
            if (double23 > 0.01) {
                final double double24 = 0.06;
                this.setDeltaMovement(cvl14.add(cvl14.x / double23 * 0.06, 0.0, cvl14.z / double23 * 0.06));
            }
            else {
                final Vec3 cvl15 = this.getDeltaMovement();
                double double25 = cvl15.x;
                double double26 = cvl15.z;
                if (bzn17 == RailShape.EAST_WEST) {
                    if (this.isRedstoneConductor(fk.west())) {
                        double25 = 0.02;
                    }
                    else if (this.isRedstoneConductor(fk.east())) {
                        double25 = -0.02;
                    }
                }
                else {
                    if (bzn17 != RailShape.NORTH_SOUTH) {
                        return;
                    }
                    if (this.isRedstoneConductor(fk.north())) {
                        double26 = 0.02;
                    }
                    else if (this.isRedstoneConductor(fk.south())) {
                        double26 = -0.02;
                    }
                }
                this.setDeltaMovement(double25, cvl15.y, double26);
            }
        }
    }
    
    private boolean isRedstoneConductor(final BlockPos fk) {
        return this.level.getBlockState(fk).isRedstoneConductor(this.level, fk);
    }
    
    protected void applyNaturalSlowdown() {
        final double double2 = this.isVehicle() ? 0.997 : 0.96;
        this.setDeltaMovement(this.getDeltaMovement().multiply(double2, 0.0, double2));
    }
    
    @Nullable
    public Vec3 getPosOffs(double double1, double double2, double double3, final double double4) {
        final int integer10 = Mth.floor(double1);
        int integer11 = Mth.floor(double2);
        final int integer12 = Mth.floor(double3);
        if (this.level.getBlockState(new BlockPos(integer10, integer11 - 1, integer12)).is(BlockTags.RAILS)) {
            --integer11;
        }
        final BlockState byj13 = this.level.getBlockState(new BlockPos(integer10, integer11, integer12));
        if (byj13.is(BlockTags.RAILS)) {
            final RailShape bzn14 = byj13.<RailShape>getValue(((BaseRailBlock)byj13.getBlock()).getShapeProperty());
            double2 = integer11;
            if (bzn14.isAscending()) {
                double2 = integer11 + 1;
            }
            final Pair<Vec3i, Vec3i> pair15 = exits(bzn14);
            final Vec3i gg16 = (Vec3i)pair15.getFirst();
            final Vec3i gg17 = (Vec3i)pair15.getSecond();
            double double5 = gg17.getX() - gg16.getX();
            double double6 = gg17.getZ() - gg16.getZ();
            final double double7 = Math.sqrt(double5 * double5 + double6 * double6);
            double5 /= double7;
            double6 /= double7;
            double1 += double5 * double4;
            double3 += double6 * double4;
            if (gg16.getY() != 0 && Mth.floor(double1) - integer10 == gg16.getX() && Mth.floor(double3) - integer12 == gg16.getZ()) {
                double2 += gg16.getY();
            }
            else if (gg17.getY() != 0 && Mth.floor(double1) - integer10 == gg17.getX() && Mth.floor(double3) - integer12 == gg17.getZ()) {
                double2 += gg17.getY();
            }
            return this.getPos(double1, double2, double3);
        }
        return null;
    }
    
    @Nullable
    public Vec3 getPos(double double1, double double2, double double3) {
        final int integer8 = Mth.floor(double1);
        int integer9 = Mth.floor(double2);
        final int integer10 = Mth.floor(double3);
        if (this.level.getBlockState(new BlockPos(integer8, integer9 - 1, integer10)).is(BlockTags.RAILS)) {
            --integer9;
        }
        final BlockState byj11 = this.level.getBlockState(new BlockPos(integer8, integer9, integer10));
        if (byj11.is(BlockTags.RAILS)) {
            final RailShape bzn12 = byj11.<RailShape>getValue(((BaseRailBlock)byj11.getBlock()).getShapeProperty());
            final Pair<Vec3i, Vec3i> pair13 = exits(bzn12);
            final Vec3i gg14 = (Vec3i)pair13.getFirst();
            final Vec3i gg15 = (Vec3i)pair13.getSecond();
            final double double4 = integer8 + 0.5 + gg14.getX() * 0.5;
            final double double5 = integer9 + 0.0625 + gg14.getY() * 0.5;
            final double double6 = integer10 + 0.5 + gg14.getZ() * 0.5;
            final double double7 = integer8 + 0.5 + gg15.getX() * 0.5;
            final double double8 = integer9 + 0.0625 + gg15.getY() * 0.5;
            final double double9 = integer10 + 0.5 + gg15.getZ() * 0.5;
            final double double10 = double7 - double4;
            final double double11 = (double8 - double5) * 2.0;
            final double double12 = double9 - double6;
            double double13;
            if (double10 == 0.0) {
                double13 = double3 - integer10;
            }
            else if (double12 == 0.0) {
                double13 = double1 - integer8;
            }
            else {
                final double double14 = double1 - double4;
                final double double15 = double3 - double6;
                double13 = (double14 * double10 + double15 * double12) * 2.0;
            }
            double1 = double4 + double10 * double13;
            double2 = double5 + double11 * double13;
            double3 = double6 + double12 * double13;
            if (double11 < 0.0) {
                ++double2;
            }
            else if (double11 > 0.0) {
                double2 += 0.5;
            }
            return new Vec3(double1, double2, double3);
        }
        return null;
    }
    
    @Override
    public AABB getBoundingBoxForCulling() {
        final AABB cvf2 = this.getBoundingBox();
        if (this.hasCustomDisplay()) {
            return cvf2.inflate(Math.abs(this.getDisplayOffset()) / 16.0);
        }
        return cvf2;
    }
    
    @Override
    protected void readAdditionalSaveData(final CompoundTag jt) {
        if (jt.getBoolean("CustomDisplayTile")) {
            this.setDisplayBlockState(NbtUtils.readBlockState(jt.getCompound("DisplayState")));
            this.setDisplayOffset(jt.getInt("DisplayOffset"));
        }
    }
    
    @Override
    protected void addAdditionalSaveData(final CompoundTag jt) {
        if (this.hasCustomDisplay()) {
            jt.putBoolean("CustomDisplayTile", true);
            jt.put("DisplayState", NbtUtils.writeBlockState(this.getDisplayBlockState()));
            jt.putInt("DisplayOffset", this.getDisplayOffset());
        }
    }
    
    @Override
    public void push(final Entity akq) {
        if (this.level.isClientSide) {
            return;
        }
        if (akq.noPhysics || this.noPhysics) {
            return;
        }
        if (this.hasPassenger(akq)) {
            return;
        }
        double double3 = akq.getX() - this.getX();
        double double4 = akq.getZ() - this.getZ();
        double double5 = double3 * double3 + double4 * double4;
        if (double5 >= 9.999999747378752E-5) {
            double5 = Mth.sqrt(double5);
            double3 /= double5;
            double4 /= double5;
            double double6 = 1.0 / double5;
            if (double6 > 1.0) {
                double6 = 1.0;
            }
            double3 *= double6;
            double4 *= double6;
            double3 *= 0.10000000149011612;
            double4 *= 0.10000000149011612;
            double3 *= 1.0f - this.pushthrough;
            double4 *= 1.0f - this.pushthrough;
            double3 *= 0.5;
            double4 *= 0.5;
            if (akq instanceof AbstractMinecart) {
                final double double7 = akq.getX() - this.getX();
                final double double8 = akq.getZ() - this.getZ();
                final Vec3 cvl15 = new Vec3(double7, 0.0, double8).normalize();
                final Vec3 cvl16 = new Vec3(Mth.cos(this.yRot * 0.017453292f), 0.0, Mth.sin(this.yRot * 0.017453292f)).normalize();
                final double double9 = Math.abs(cvl15.dot(cvl16));
                if (double9 < 0.800000011920929) {
                    return;
                }
                final Vec3 cvl17 = this.getDeltaMovement();
                final Vec3 cvl18 = akq.getDeltaMovement();
                if (((AbstractMinecart)akq).getMinecartType() == Type.FURNACE && this.getMinecartType() != Type.FURNACE) {
                    this.setDeltaMovement(cvl17.multiply(0.2, 1.0, 0.2));
                    this.push(cvl18.x - double3, 0.0, cvl18.z - double4);
                    akq.setDeltaMovement(cvl18.multiply(0.95, 1.0, 0.95));
                }
                else if (((AbstractMinecart)akq).getMinecartType() != Type.FURNACE && this.getMinecartType() == Type.FURNACE) {
                    akq.setDeltaMovement(cvl18.multiply(0.2, 1.0, 0.2));
                    akq.push(cvl17.x + double3, 0.0, cvl17.z + double4);
                    this.setDeltaMovement(cvl17.multiply(0.95, 1.0, 0.95));
                }
                else {
                    final double double10 = (cvl18.x + cvl17.x) / 2.0;
                    final double double11 = (cvl18.z + cvl17.z) / 2.0;
                    this.setDeltaMovement(cvl17.multiply(0.2, 1.0, 0.2));
                    this.push(double10 - double3, 0.0, double11 - double4);
                    akq.setDeltaMovement(cvl18.multiply(0.2, 1.0, 0.2));
                    akq.push(double10 + double3, 0.0, double11 + double4);
                }
            }
            else {
                this.push(-double3, 0.0, -double4);
                akq.push(double3 / 4.0, 0.0, double4 / 4.0);
            }
        }
    }
    
    @Override
    public void lerpTo(final double double1, final double double2, final double double3, final float float4, final float float5, final int integer, final boolean boolean7) {
        this.lx = double1;
        this.ly = double2;
        this.lz = double3;
        this.lyr = float4;
        this.lxr = float5;
        this.lSteps = integer + 2;
        this.setDeltaMovement(this.lxd, this.lyd, this.lzd);
    }
    
    @Override
    public void lerpMotion(final double double1, final double double2, final double double3) {
        this.lxd = double1;
        this.lyd = double2;
        this.lzd = double3;
        this.setDeltaMovement(this.lxd, this.lyd, this.lzd);
    }
    
    public void setDamage(final float float1) {
        this.entityData.<Float>set(AbstractMinecart.DATA_ID_DAMAGE, float1);
    }
    
    public float getDamage() {
        return this.entityData.<Float>get(AbstractMinecart.DATA_ID_DAMAGE);
    }
    
    public void setHurtTime(final int integer) {
        this.entityData.<Integer>set(AbstractMinecart.DATA_ID_HURT, integer);
    }
    
    public int getHurtTime() {
        return this.entityData.<Integer>get(AbstractMinecart.DATA_ID_HURT);
    }
    
    public void setHurtDir(final int integer) {
        this.entityData.<Integer>set(AbstractMinecart.DATA_ID_HURTDIR, integer);
    }
    
    public int getHurtDir() {
        return this.entityData.<Integer>get(AbstractMinecart.DATA_ID_HURTDIR);
    }
    
    public abstract Type getMinecartType();
    
    public BlockState getDisplayBlockState() {
        if (!this.hasCustomDisplay()) {
            return this.getDefaultDisplayBlockState();
        }
        return Block.stateById(this.getEntityData().<Integer>get(AbstractMinecart.DATA_ID_DISPLAY_BLOCK));
    }
    
    public BlockState getDefaultDisplayBlockState() {
        return Blocks.AIR.defaultBlockState();
    }
    
    public int getDisplayOffset() {
        if (!this.hasCustomDisplay()) {
            return this.getDefaultDisplayOffset();
        }
        return this.getEntityData().<Integer>get(AbstractMinecart.DATA_ID_DISPLAY_OFFSET);
    }
    
    public int getDefaultDisplayOffset() {
        return 6;
    }
    
    public void setDisplayBlockState(final BlockState byj) {
        this.getEntityData().<Integer>set(AbstractMinecart.DATA_ID_DISPLAY_BLOCK, Block.getId(byj));
        this.setCustomDisplay(true);
    }
    
    public void setDisplayOffset(final int integer) {
        this.getEntityData().<Integer>set(AbstractMinecart.DATA_ID_DISPLAY_OFFSET, integer);
        this.setCustomDisplay(true);
    }
    
    public boolean hasCustomDisplay() {
        return this.getEntityData().<Boolean>get(AbstractMinecart.DATA_ID_CUSTOM_DISPLAY);
    }
    
    public void setCustomDisplay(final boolean boolean1) {
        this.getEntityData().<Boolean>set(AbstractMinecart.DATA_ID_CUSTOM_DISPLAY, boolean1);
    }
    
    @Override
    public Packet<?> getAddEntityPacket() {
        return new ClientboundAddEntityPacket(this);
    }
    
    static {
        DATA_ID_HURT = SynchedEntityData.<Integer>defineId(AbstractMinecart.class, EntityDataSerializers.INT);
        DATA_ID_HURTDIR = SynchedEntityData.<Integer>defineId(AbstractMinecart.class, EntityDataSerializers.INT);
        DATA_ID_DAMAGE = SynchedEntityData.<Float>defineId(AbstractMinecart.class, EntityDataSerializers.FLOAT);
        DATA_ID_DISPLAY_BLOCK = SynchedEntityData.<Integer>defineId(AbstractMinecart.class, EntityDataSerializers.INT);
        DATA_ID_DISPLAY_OFFSET = SynchedEntityData.<Integer>defineId(AbstractMinecart.class, EntityDataSerializers.INT);
        DATA_ID_CUSTOM_DISPLAY = SynchedEntityData.<Boolean>defineId(AbstractMinecart.class, EntityDataSerializers.BOOLEAN);
        final Vec3i gg2;
        final Vec3i gg3;
        final Vec3i gg4;
        final Vec3i gg5;
        final Vec3i gg6;
        final Vec3i gg7;
        final Vec3i gg8;
        final Vec3i gg9;
        EXITS = Util.<Map<RailShape, Pair<Vec3i, Vec3i>>>make(Maps.newEnumMap(RailShape.class), enumMap -> {
            gg2 = Direction.WEST.getNormal();
            gg3 = Direction.EAST.getNormal();
            gg4 = Direction.NORTH.getNormal();
            gg5 = Direction.SOUTH.getNormal();
            gg6 = gg2.below();
            gg7 = gg3.below();
            gg8 = gg4.below();
            gg9 = gg5.below();
            enumMap.put(RailShape.NORTH_SOUTH, Pair.of(gg4, gg5));
            enumMap.put(RailShape.EAST_WEST, Pair.of(gg2, gg3));
            enumMap.put(RailShape.ASCENDING_EAST, Pair.of(gg6, gg3));
            enumMap.put(RailShape.ASCENDING_WEST, Pair.of(gg2, gg7));
            enumMap.put(RailShape.ASCENDING_NORTH, Pair.of(gg4, gg9));
            enumMap.put(RailShape.ASCENDING_SOUTH, Pair.of(gg8, gg5));
            enumMap.put(RailShape.SOUTH_EAST, Pair.of(gg5, gg3));
            enumMap.put(RailShape.SOUTH_WEST, Pair.of(gg5, gg2));
            enumMap.put(RailShape.NORTH_WEST, Pair.of(gg4, gg2));
            enumMap.put(RailShape.NORTH_EAST, Pair.of(gg4, gg3));
        });
    }
    
    public enum Type {
        RIDEABLE, 
        CHEST, 
        FURNACE, 
        TNT, 
        SPAWNER, 
        HOPPER, 
        COMMAND_BLOCK;
    }
}
