aboutsummaryrefslogtreecommitdiffhomepage
path: root/patch-remap/mache-spigotflower/net/minecraft/world/entity/vehicle/AbstractMinecart.java.patch
diff options
context:
space:
mode:
Diffstat (limited to 'patch-remap/mache-spigotflower/net/minecraft/world/entity/vehicle/AbstractMinecart.java.patch')
-rw-r--r--patch-remap/mache-spigotflower/net/minecraft/world/entity/vehicle/AbstractMinecart.java.patch1114
1 files changed, 1114 insertions, 0 deletions
diff --git a/patch-remap/mache-spigotflower/net/minecraft/world/entity/vehicle/AbstractMinecart.java.patch b/patch-remap/mache-spigotflower/net/minecraft/world/entity/vehicle/AbstractMinecart.java.patch
new file mode 100644
index 0000000000..8263cb526d
--- /dev/null
+++ b/patch-remap/mache-spigotflower/net/minecraft/world/entity/vehicle/AbstractMinecart.java.patch
@@ -0,0 +1,1114 @@
+--- a/net/minecraft/world/entity/vehicle/AbstractMinecart.java
++++ b/net/minecraft/world/entity/vehicle/AbstractMinecart.java
+@@ -25,11 +25,11 @@
+ import net.minecraft.util.Mth;
+ import net.minecraft.world.entity.Entity;
+ import net.minecraft.world.entity.EntityDimensions;
++import net.minecraft.world.entity.EntityPose;
+ import net.minecraft.world.entity.EntitySelector;
+ import net.minecraft.world.entity.EntityType;
++import net.minecraft.world.entity.EnumMoveType;
+ import net.minecraft.world.entity.LivingEntity;
+-import net.minecraft.world.entity.MoverType;
+-import net.minecraft.world.entity.Pose;
+ import net.minecraft.world.entity.animal.IronGolem;
+ import net.minecraft.world.entity.npc.Villager;
+ import net.minecraft.world.entity.npc.WanderingTrader;
+@@ -42,12 +42,20 @@
+ import net.minecraft.world.level.block.Block;
+ import net.minecraft.world.level.block.Blocks;
+ import net.minecraft.world.level.block.PoweredRailBlock;
+-import net.minecraft.world.level.block.state.BlockState;
++import net.minecraft.world.level.block.state.IBlockData;
+ import net.minecraft.world.level.block.state.properties.RailShape;
+ import net.minecraft.world.phys.AABB;
+ import net.minecraft.world.phys.Vec3;
+ import org.joml.Vector3f;
+
++// CraftBukkit start
++import org.bukkit.Location;
++import org.bukkit.craftbukkit.util.CraftLocation;
++import org.bukkit.entity.Vehicle;
++import org.bukkit.event.vehicle.VehicleEntityCollisionEvent;
++import org.bukkit.util.Vector;
++// CraftBukkit end
++
+ public abstract class AbstractMinecart extends VehicleEntity {
+
+ private static final float LOWERED_PASSENGER_ATTACHMENT_Y = 0.0F;
+@@ -55,7 +63,7 @@
+ private static final EntityDataAccessor<Integer> DATA_ID_DISPLAY_BLOCK = SynchedEntityData.defineId(AbstractMinecart.class, EntityDataSerializers.INT);
+ private static final EntityDataAccessor<Integer> DATA_ID_DISPLAY_OFFSET = SynchedEntityData.defineId(AbstractMinecart.class, EntityDataSerializers.INT);
+ private static final EntityDataAccessor<Boolean> DATA_ID_CUSTOM_DISPLAY = SynchedEntityData.defineId(AbstractMinecart.class, EntityDataSerializers.BOOLEAN);
+- private static final ImmutableMap<Pose, ImmutableList<Integer>> POSE_DISMOUNT_HEIGHTS = ImmutableMap.of(Pose.STANDING, ImmutableList.of(0, 1, -1), Pose.CROUCHING, ImmutableList.of(0, 1, -1), Pose.SWIMMING, ImmutableList.of(0, 1));
++ private static final ImmutableMap<EntityPose, ImmutableList<Integer>> POSE_DISMOUNT_HEIGHTS = ImmutableMap.of(EntityPose.STANDING, ImmutableList.of(0, 1, -1), EntityPose.CROUCHING, ImmutableList.of(0, 1, -1), EntityPose.SWIMMING, ImmutableList.of(0, 1));
+ protected static final float WATER_SLOWDOWN_FACTOR = 0.95F;
+ private boolean flipped;
+ private boolean onRails;
+@@ -67,81 +75,90 @@
+ private double lerpXRot;
+ private Vec3 targetDeltaMovement;
+ private static final Map<RailShape, Pair<Vec3i, Vec3i>> EXITS = (Map) Util.make(Maps.newEnumMap(RailShape.class), (enummap) -> {
+- Vec3i vec3i = Direction.WEST.getNormal();
+- Vec3i vec3i1 = Direction.EAST.getNormal();
+- Vec3i vec3i2 = Direction.NORTH.getNormal();
+- Vec3i vec3i3 = Direction.SOUTH.getNormal();
+- Vec3i vec3i4 = vec3i.below();
+- Vec3i vec3i5 = vec3i1.below();
+- Vec3i vec3i6 = vec3i2.below();
+- Vec3i vec3i7 = vec3i3.below();
++ Vec3i baseblockposition = Direction.WEST.getNormal();
++ Vec3i baseblockposition1 = Direction.EAST.getNormal();
++ Vec3i baseblockposition2 = Direction.NORTH.getNormal();
++ Vec3i baseblockposition3 = Direction.SOUTH.getNormal();
++ Vec3i baseblockposition4 = baseblockposition.below();
++ Vec3i baseblockposition5 = baseblockposition1.below();
++ Vec3i baseblockposition6 = baseblockposition2.below();
++ Vec3i baseblockposition7 = baseblockposition3.below();
+
+- enummap.put(RailShape.NORTH_SOUTH, Pair.of(vec3i2, vec3i3));
+- enummap.put(RailShape.EAST_WEST, Pair.of(vec3i, vec3i1));
+- enummap.put(RailShape.ASCENDING_EAST, Pair.of(vec3i4, vec3i1));
+- enummap.put(RailShape.ASCENDING_WEST, Pair.of(vec3i, vec3i5));
+- enummap.put(RailShape.ASCENDING_NORTH, Pair.of(vec3i2, vec3i7));
+- enummap.put(RailShape.ASCENDING_SOUTH, Pair.of(vec3i6, vec3i3));
+- enummap.put(RailShape.SOUTH_EAST, Pair.of(vec3i3, vec3i1));
+- enummap.put(RailShape.SOUTH_WEST, Pair.of(vec3i3, vec3i));
+- enummap.put(RailShape.NORTH_WEST, Pair.of(vec3i2, vec3i));
+- enummap.put(RailShape.NORTH_EAST, Pair.of(vec3i2, vec3i1));
++ enummap.put(RailShape.NORTH_SOUTH, Pair.of(baseblockposition2, baseblockposition3));
++ enummap.put(RailShape.EAST_WEST, Pair.of(baseblockposition, baseblockposition1));
++ enummap.put(RailShape.ASCENDING_EAST, Pair.of(baseblockposition4, baseblockposition1));
++ enummap.put(RailShape.ASCENDING_WEST, Pair.of(baseblockposition, baseblockposition5));
++ enummap.put(RailShape.ASCENDING_NORTH, Pair.of(baseblockposition2, baseblockposition7));
++ enummap.put(RailShape.ASCENDING_SOUTH, Pair.of(baseblockposition6, baseblockposition3));
++ enummap.put(RailShape.SOUTH_EAST, Pair.of(baseblockposition3, baseblockposition1));
++ enummap.put(RailShape.SOUTH_WEST, Pair.of(baseblockposition3, baseblockposition));
++ enummap.put(RailShape.NORTH_WEST, Pair.of(baseblockposition2, baseblockposition));
++ enummap.put(RailShape.NORTH_EAST, Pair.of(baseblockposition2, baseblockposition1));
+ });
+
+- protected AbstractMinecart(EntityType<?> entitytype, Level level) {
+- super(entitytype, level);
++ // CraftBukkit start
++ public boolean slowWhenEmpty = true;
++ private double derailedX = 0.5;
++ private double derailedY = 0.5;
++ private double derailedZ = 0.5;
++ private double flyingX = 0.95;
++ private double flyingY = 0.95;
++ private double flyingZ = 0.95;
++ public double maxSpeed = 0.4D;
++ // CraftBukkit end
++
++ protected AbstractMinecart(EntityType<?> entityType, Level level) {
++ super(entityType, level);
+ this.targetDeltaMovement = Vec3.ZERO;
+ this.blocksBuilding = true;
+ }
+
+- protected AbstractMinecart(EntityType<?> entitytype, Level level, double d0, double d1, double d2) {
+- this(entitytype, level);
+- this.setPos(d0, d1, d2);
+- this.xo = d0;
++ protected AbstractMinecart(EntityType<?> entityType, Level level, double x, double d1, double y) {
++ this(entityType, level);
++ this.setPos(x, d1, y);
++ this.xo = x;
+ this.yo = d1;
+- this.zo = d2;
++ this.zo = y;
+ }
+
+- public static AbstractMinecart createMinecart(ServerLevel serverlevel, double d0, double d1, double d2, AbstractMinecart.Type abstractminecart_type, ItemStack itemstack, @Nullable Player player) {
++ public static AbstractMinecart createMinecart(ServerLevel worldserver, double d0, double d1, double d2, AbstractMinecart.EnumMinecartType entityminecartabstract_enumminecarttype, ItemStack itemstack, @Nullable Player entityhuman) {
+ Object object;
+
+- switch (abstractminecart_type) {
++ switch (entityminecartabstract_enumminecarttype) {
+ case CHEST:
+- object = new MinecartChest(serverlevel, d0, d1, d2);
++ object = new MinecartChest(worldserver, d0, d1, d2);
+ break;
+ case FURNACE:
+- object = new MinecartFurnace(serverlevel, d0, d1, d2);
++ object = new MinecartFurnace(worldserver, d0, d1, d2);
+ break;
+ case TNT:
+- object = new MinecartTNT(serverlevel, d0, d1, d2);
++ object = new MinecartTNT(worldserver, d0, d1, d2);
+ break;
+ case SPAWNER:
+- object = new MinecartSpawner(serverlevel, d0, d1, d2);
++ object = new MinecartSpawner(worldserver, d0, d1, d2);
+ break;
+ case HOPPER:
+- object = new MinecartHopper(serverlevel, d0, d1, d2);
++ object = new MinecartHopper(worldserver, d0, d1, d2);
+ break;
+ case COMMAND_BLOCK:
+- object = new MinecartCommandBlock(serverlevel, d0, d1, d2);
++ object = new MinecartCommandBlock(worldserver, d0, d1, d2);
+ break;
+ default:
+- object = new Minecart(serverlevel, d0, d1, d2);
++ object = new Minecart(worldserver, d0, d1, d2);
+ }
+
+- Object object1 = object;
++ AbstractMinecart object1 = (AbstractMinecart) object; // CraftBukkit- decompile error
+
+- EntityType.createDefaultStackConfig(serverlevel, itemstack, player).accept(object1);
++ EntityType.createDefaultStackConfig(worldserver, itemstack, entityhuman).accept(object1);
+ return (AbstractMinecart) object1;
+ }
+
+ @Override
+- @Override
+ protected Entity.MovementEmission getMovementEmission() {
+ return Entity.MovementEmission.EVENTS;
+ }
+
+ @Override
+- @Override
+ protected void defineSynchedData() {
+ super.defineSynchedData();
+ this.entityData.define(AbstractMinecart.DATA_ID_DISPLAY_BLOCK, Block.getId(Blocks.AIR.defaultBlockState()));
+@@ -150,50 +167,45 @@
+ }
+
+ @Override
+- @Override
+ public boolean canCollideWith(Entity entity) {
+ return Boat.canVehicleCollide(this, entity);
+ }
+
+ @Override
+- @Override
+ public boolean isPushable() {
+ return true;
+ }
+
+ @Override
+- @Override
+- protected Vec3 getRelativePortalPosition(Direction.Axis direction_axis, BlockUtil.FoundRectangle blockutil_foundrectangle) {
+- return LivingEntity.resetForwardDirectionOfRelativePortalPosition(super.getRelativePortalPosition(direction_axis, blockutil_foundrectangle));
++ protected Vec3 getRelativePortalPosition(Direction.Axis axis, BlockUtil.FoundRectangle portal) {
++ return LivingEntity.resetForwardDirectionOfRelativePortalPosition(super.getRelativePortalPosition(axis, portal));
+ }
+
+ @Override
+- @Override
+- protected Vector3f getPassengerAttachmentPoint(Entity entity, EntityDimensions entitydimensions, float f) {
++ protected Vector3f getPassengerAttachmentPoint(Entity entity, EntityDimensions entitysize, float f) {
+ boolean flag = entity instanceof Villager || entity instanceof WanderingTrader;
+
+ return new Vector3f(0.0F, flag ? 0.0F : 0.1875F, 0.0F);
+ }
+
+ @Override
+- @Override
+- public Vec3 getDismountLocationForPassenger(LivingEntity livingentity) {
+- Direction direction = this.getMotionDirection();
++ public Vec3 getDismountLocationForPassenger(LivingEntity livingEntity) {
++ Direction enumdirection = this.getMotionDirection();
+
+- if (direction.getAxis() == Direction.Axis.Y) {
+- return super.getDismountLocationForPassenger(livingentity);
++ if (enumdirection.getAxis() == Direction.Axis.Y) {
++ return super.getDismountLocationForPassenger(livingEntity);
+ } else {
+- int[][] aint = DismountHelper.offsetsForDirection(direction);
+- BlockPos blockpos = this.blockPosition();
+- BlockPos.MutableBlockPos blockpos_mutableblockpos = new BlockPos.MutableBlockPos();
+- ImmutableList<Pose> immutablelist = livingentity.getDismountPoses();
++ int[][] aint = DismountHelper.offsetsForDirection(enumdirection);
++ BlockPos blockposition = this.blockPosition();
++ BlockPos.MutableBlockPos blockposition_mutableblockposition = new BlockPos.MutableBlockPos();
++ ImmutableList<EntityPose> immutablelist = livingEntity.getDismountPoses();
+ UnmodifiableIterator unmodifiableiterator = immutablelist.iterator();
+
+ while (unmodifiableiterator.hasNext()) {
+- Pose pose = (Pose) unmodifiableiterator.next();
+- EntityDimensions entitydimensions = livingentity.getDimensions(pose);
+- float f = Math.min(entitydimensions.width, 1.0F) / 2.0F;
+- UnmodifiableIterator unmodifiableiterator1 = ((ImmutableList) AbstractMinecart.POSE_DISMOUNT_HEIGHTS.get(pose)).iterator();
++ EntityPose entitypose = (EntityPose) unmodifiableiterator.next();
++ EntityDimensions entitysize = livingEntity.getDimensions(entitypose);
++ float f = Math.min(entitysize.width, 1.0F) / 2.0F;
++ UnmodifiableIterator unmodifiableiterator1 = ((ImmutableList) AbstractMinecart.POSE_DISMOUNT_HEIGHTS.get(entitypose)).iterator();
+
+ while (unmodifiableiterator1.hasNext()) {
+ int i = (Integer) unmodifiableiterator1.next();
+@@ -203,18 +215,18 @@
+ for (int k = 0; k < j; ++k) {
+ int[] aint2 = aint1[k];
+
+- blockpos_mutableblockpos.set(blockpos.getX() + aint2[0], blockpos.getY() + i, blockpos.getZ() + aint2[1]);
+- double d0 = this.level().getBlockFloorHeight(DismountHelper.nonClimbableShape(this.level(), blockpos_mutableblockpos), () -> {
+- return DismountHelper.nonClimbableShape(this.level(), blockpos_mutableblockpos.below());
++ blockposition_mutableblockposition.set(blockposition.getX() + aint2[0], blockposition.getY() + i, blockposition.getZ() + aint2[1]);
++ double d0 = this.level().getBlockFloorHeight(DismountHelper.nonClimbableShape(this.level(), blockposition_mutableblockposition), () -> {
++ return DismountHelper.nonClimbableShape(this.level(), blockposition_mutableblockposition.below());
+ });
+
+ if (DismountHelper.isBlockFloorValid(d0)) {
+- AABB aabb = new AABB((double) (-f), 0.0D, (double) (-f), (double) f, (double) entitydimensions.height, (double) f);
+- Vec3 vec3 = Vec3.upFromBottomCenterOf(blockpos_mutableblockpos, d0);
++ AABB axisalignedbb = new AABB((double) (-f), 0.0D, (double) (-f), (double) f, (double) entitysize.height, (double) f);
++ Vec3 vec3d = Vec3.upFromBottomCenterOf(blockposition_mutableblockposition, d0);
+
+- if (DismountHelper.canDismountTo(this.level(), livingentity, aabb.move(vec3))) {
+- livingentity.setPose(pose);
+- return vec3;
++ if (DismountHelper.canDismountTo(this.level(), livingEntity, axisalignedbb.move(vec3d))) {
++ livingEntity.setPose(entitypose);
++ return vec3d;
+ }
+ }
+ }
+@@ -223,62 +235,65 @@
+
+ double d1 = this.getBoundingBox().maxY;
+
+- blockpos_mutableblockpos.set((double) blockpos.getX(), d1, (double) blockpos.getZ());
++ blockposition_mutableblockposition.set((double) blockposition.getX(), d1, (double) blockposition.getZ());
+ UnmodifiableIterator unmodifiableiterator2 = immutablelist.iterator();
+
+ while (unmodifiableiterator2.hasNext()) {
+- Pose pose1 = (Pose) unmodifiableiterator2.next();
+- double d2 = (double) livingentity.getDimensions(pose1).height;
+- int l = Mth.ceil(d1 - (double) blockpos_mutableblockpos.getY() + d2);
+- double d3 = DismountHelper.findCeilingFrom(blockpos_mutableblockpos, l, (blockpos1) -> {
+- return this.level().getBlockState(blockpos1).getCollisionShape(this.level(), blockpos1);
++ EntityPose entitypose1 = (EntityPose) unmodifiableiterator2.next();
++ double d2 = (double) livingEntity.getDimensions(entitypose1).height;
++ int l = Mth.ceil(d1 - (double) blockposition_mutableblockposition.getY() + d2);
++ double d3 = DismountHelper.findCeilingFrom(blockposition_mutableblockposition, l, (blockposition1) -> {
++ return this.level().getBlockState(blockposition1).getCollisionShape(this.level(), blockposition1);
+ });
+
+ if (d1 + d2 <= d3) {
+- livingentity.setPose(pose1);
++ livingEntity.setPose(entitypose1);
+ break;
+ }
+ }
+
+- return super.getDismountLocationForPassenger(livingentity);
++ return super.getDismountLocationForPassenger(livingEntity);
+ }
+ }
+
+ @Override
+- @Override
+ protected float getBlockSpeedFactor() {
+- BlockState blockstate = this.level().getBlockState(this.blockPosition());
++ IBlockData iblockdata = this.level().getBlockState(this.blockPosition());
+
+- return blockstate.is(BlockTags.RAILS) ? 1.0F : super.getBlockSpeedFactor();
++ return iblockdata.is(BlockTags.RAILS) ? 1.0F : super.getBlockSpeedFactor();
+ }
+
+ @Override
+- @Override
+- public void animateHurt(float f) {
++ public void animateHurt(float yaw) {
+ this.setHurtDir(-this.getHurtDir());
+ this.setHurtTime(10);
+ this.setDamage(this.getDamage() + this.getDamage() * 10.0F);
+ }
+
+ @Override
+- @Override
+ public boolean isPickable() {
+ return !this.isRemoved();
+ }
+
+- private static Pair<Vec3i, Vec3i> exits(RailShape railshape) {
+- return (Pair) AbstractMinecart.EXITS.get(railshape);
++ private static Pair<Vec3i, Vec3i> exits(RailShape shape) {
++ return (Pair) AbstractMinecart.EXITS.get(shape);
+ }
+
+ @Override
+- @Override
+ public Direction getMotionDirection() {
+ return this.flipped ? this.getDirection().getOpposite().getClockWise() : this.getDirection().getClockWise();
+ }
+
+ @Override
+- @Override
+ public void tick() {
++ // CraftBukkit start
++ double prevX = this.getX();
++ double prevY = this.getY();
++ double prevZ = this.getZ();
++ float prevYaw = this.getYRot();
++ float prevPitch = this.getXRot();
++ // CraftBukkit end
++
+ if (this.getHurtTime() > 0) {
+ this.setHurtTime(this.getHurtTime() - 1);
+ }
+@@ -288,7 +303,7 @@
+ }
+
+ this.checkBelowWorld();
+- this.handleNetherPortal();
++ // this.handleNetherPortal(); // CraftBukkit - handled in postTick
+ if (this.level().isClientSide) {
+ if (this.lerpSteps > 0) {
+ this.lerpPositionAndRotationStep(this.lerpSteps, this.lerpX, this.lerpY, this.lerpZ, this.lerpYRot, this.lerpXRot);
+@@ -313,14 +328,14 @@
+ --j;
+ }
+
+- BlockPos blockpos = new BlockPos(i, j, k);
+- BlockState blockstate = this.level().getBlockState(blockpos);
++ BlockPos blockposition = new BlockPos(i, j, k);
++ IBlockData iblockdata = this.level().getBlockState(blockposition);
+
+- this.onRails = BaseRailBlock.isRail(blockstate);
++ this.onRails = BaseRailBlock.isRail(iblockdata);
+ if (this.onRails) {
+- this.moveAlongTrack(blockpos, blockstate);
+- if (blockstate.is(Blocks.ACTIVATOR_RAIL)) {
+- this.activateMinecart(i, j, k, (Boolean) blockstate.getValue(PoweredRailBlock.POWERED));
++ this.moveAlongTrack(blockposition, iblockdata);
++ if (iblockdata.is(Blocks.ACTIVATOR_RAIL)) {
++ this.activateMinecart(i, j, k, (Boolean) iblockdata.getValue(PoweredRailBlock.POWERED));
+ }
+ } else {
+ this.comeOffTrack();
+@@ -346,7 +361,19 @@
+ }
+
+ this.setRot(this.getYRot(), this.getXRot());
+- if (this.getMinecartType() == AbstractMinecart.Type.RIDEABLE && this.getDeltaMovement().horizontalDistanceSqr() > 0.01D) {
++ // CraftBukkit start
++ org.bukkit.World bworld = this.level().getWorld();
++ Location from = new Location(bworld, prevX, prevY, prevZ, prevYaw, prevPitch);
++ Location to = CraftLocation.toBukkit(this.position(), bworld, this.getYRot(), this.getXRot());
++ Vehicle vehicle = (Vehicle) this.getBukkitEntity();
++
++ this.level().getCraftServer().getPluginManager().callEvent(new org.bukkit.event.vehicle.VehicleUpdateEvent(vehicle));
++
++ if (!from.equals(to)) {
++ this.level().getCraftServer().getPluginManager().callEvent(new org.bukkit.event.vehicle.VehicleMoveEvent(vehicle, from, to));
++ }
++ // CraftBukkit end
++ if (this.getMinecartType() == AbstractMinecart.EnumMinecartType.RIDEABLE && this.getDeltaMovement().horizontalDistanceSqr() > 0.01D) {
+ List<Entity> list = this.level().getEntities((Entity) this, this.getBoundingBox().inflate(0.20000000298023224D, 0.0D, 0.20000000298023224D), EntitySelector.pushableBy(this));
+
+ if (!list.isEmpty()) {
+@@ -356,8 +383,26 @@
+ Entity entity = (Entity) iterator.next();
+
+ if (!(entity instanceof Player) && !(entity instanceof IronGolem) && !(entity instanceof AbstractMinecart) && !this.isVehicle() && !entity.isPassenger()) {
++ // CraftBukkit start
++ VehicleEntityCollisionEvent collisionEvent = new VehicleEntityCollisionEvent(vehicle, entity.getBukkitEntity());
++ this.level().getCraftServer().getPluginManager().callEvent(collisionEvent);
++
++ if (collisionEvent.isCancelled()) {
++ continue;
++ }
++ // CraftBukkit end
+ entity.startRiding(this);
+ } else {
++ // CraftBukkit start
++ if (!this.isPassengerOfSameVehicle(entity)) {
++ VehicleEntityCollisionEvent collisionEvent = new VehicleEntityCollisionEvent(vehicle, entity.getBukkitEntity());
++ this.level().getCraftServer().getPluginManager().callEvent(collisionEvent);
++
++ if (collisionEvent.isCancelled()) {
++ continue;
++ }
++ }
++ // CraftBukkit end
+ entity.push(this);
+ }
+ }
+@@ -369,6 +414,14 @@
+ Entity entity1 = (Entity) iterator1.next();
+
+ if (!this.hasPassenger(entity1) && entity1.isPushable() && entity1 instanceof AbstractMinecart) {
++ // CraftBukkit start
++ VehicleEntityCollisionEvent collisionEvent = new VehicleEntityCollisionEvent(vehicle, entity1.getBukkitEntity());
++ this.level().getCraftServer().getPluginManager().callEvent(collisionEvent);
++
++ if (collisionEvent.isCancelled()) {
++ continue;
++ }
++ // CraftBukkit end
+ entity1.push(this);
+ }
+ }
+@@ -385,40 +438,44 @@
+ }
+
+ protected double getMaxSpeed() {
+- return (this.isInWater() ? 4.0D : 8.0D) / 20.0D;
++ return (this.isInWater() ? this.maxSpeed / 2.0D: this.maxSpeed); // CraftBukkit
+ }
+
+- public void activateMinecart(int i, int j, int k, boolean flag) {}
++ public void activateMinecart(int x, int y, int z, boolean powered) {}
+
+ protected void comeOffTrack() {
+ double d0 = this.getMaxSpeed();
+- Vec3 vec3 = this.getDeltaMovement();
++ Vec3 vec3d = this.getDeltaMovement();
+
+- this.setDeltaMovement(Mth.clamp(vec3.x, -d0, d0), vec3.y, Mth.clamp(vec3.z, -d0, d0));
++ this.setDeltaMovement(Mth.clamp(vec3d.x, -d0, d0), vec3d.y, Mth.clamp(vec3d.z, -d0, d0));
+ if (this.onGround()) {
+- this.setDeltaMovement(this.getDeltaMovement().scale(0.5D));
++ // CraftBukkit start - replace magic numbers with our variables
++ this.setDeltaMovement(new Vec3(this.getDeltaMovement().x * this.derailedX, this.getDeltaMovement().y * this.derailedY, this.getDeltaMovement().z * this.derailedZ));
++ // CraftBukkit end
+ }
+
+- this.move(MoverType.SELF, this.getDeltaMovement());
++ this.move(EnumMoveType.SELF, this.getDeltaMovement());
+ if (!this.onGround()) {
+- this.setDeltaMovement(this.getDeltaMovement().scale(0.95D));
++ // CraftBukkit start - replace magic numbers with our variables
++ this.setDeltaMovement(new Vec3(this.getDeltaMovement().x * this.flyingX, this.getDeltaMovement().y * this.flyingY, this.getDeltaMovement().z * this.flyingZ));
++ // CraftBukkit end
+ }
+
+ }
+
+- protected void moveAlongTrack(BlockPos blockpos, BlockState blockstate) {
++ protected void moveAlongTrack(BlockPos pos, IBlockData state) {
+ this.resetFallDistance();
+ double d0 = this.getX();
+ double d1 = this.getY();
+ double d2 = this.getZ();
+- Vec3 vec3 = this.getPos(d0, d1, d2);
++ Vec3 vec3d = this.getPos(d0, d1, d2);
+
+- d1 = (double) blockpos.getY();
++ d1 = (double) pos.getY();
+ boolean flag = false;
+ boolean flag1 = false;
+
+- if (blockstate.is(Blocks.POWERED_RAIL)) {
+- flag = (Boolean) blockstate.getValue(PoweredRailBlock.POWERED);
++ if (state.is(Blocks.POWERED_RAIL)) {
++ flag = (Boolean) state.getValue(PoweredRailBlock.POWERED);
+ flag1 = !flag;
+ }
+
+@@ -428,54 +485,54 @@
+ d3 *= 0.2D;
+ }
+
+- Vec3 vec31 = this.getDeltaMovement();
+- RailShape railshape = (RailShape) blockstate.getValue(((BaseRailBlock) blockstate.getBlock()).getShapeProperty());
++ Vec3 vec3d1 = this.getDeltaMovement();
++ RailShape blockpropertytrackposition = (RailShape) state.getValue(((BaseRailBlock) state.getBlock()).getShapeProperty());
+
+- switch (railshape) {
++ switch (blockpropertytrackposition) {
+ case ASCENDING_EAST:
+- this.setDeltaMovement(vec31.add(-d3, 0.0D, 0.0D));
++ this.setDeltaMovement(vec3d1.add(-d3, 0.0D, 0.0D));
+ ++d1;
+ break;
+ case ASCENDING_WEST:
+- this.setDeltaMovement(vec31.add(d3, 0.0D, 0.0D));
++ this.setDeltaMovement(vec3d1.add(d3, 0.0D, 0.0D));
+ ++d1;
+ break;
+ case ASCENDING_NORTH:
+- this.setDeltaMovement(vec31.add(0.0D, 0.0D, d3));
++ this.setDeltaMovement(vec3d1.add(0.0D, 0.0D, d3));
+ ++d1;
+ break;
+ case ASCENDING_SOUTH:
+- this.setDeltaMovement(vec31.add(0.0D, 0.0D, -d3));
++ this.setDeltaMovement(vec3d1.add(0.0D, 0.0D, -d3));
+ ++d1;
+ }
+
+- vec31 = this.getDeltaMovement();
+- Pair<Vec3i, Vec3i> pair = exits(railshape);
+- Vec3i vec3i = (Vec3i) pair.getFirst();
+- Vec3i vec3i1 = (Vec3i) pair.getSecond();
+- double d4 = (double) (vec3i1.getX() - vec3i.getX());
+- double d5 = (double) (vec3i1.getZ() - vec3i.getZ());
++ vec3d1 = this.getDeltaMovement();
++ Pair<Vec3i, Vec3i> pair = exits(blockpropertytrackposition);
++ Vec3i baseblockposition = (Vec3i) pair.getFirst();
++ Vec3i baseblockposition1 = (Vec3i) pair.getSecond();
++ double d4 = (double) (baseblockposition1.getX() - baseblockposition.getX());
++ double d5 = (double) (baseblockposition1.getZ() - baseblockposition.getZ());
+ double d6 = Math.sqrt(d4 * d4 + d5 * d5);
+- double d7 = vec31.x * d4 + vec31.z * d5;
++ double d7 = vec3d1.x * d4 + vec3d1.z * d5;
+
+ if (d7 < 0.0D) {
+ d4 = -d4;
+ d5 = -d5;
+ }
+
+- double d8 = Math.min(2.0D, vec31.horizontalDistance());
++ double d8 = Math.min(2.0D, vec3d1.horizontalDistance());
+
+- vec31 = new Vec3(d8 * d4 / d6, vec31.y, d8 * d5 / d6);
+- this.setDeltaMovement(vec31);
++ vec3d1 = new Vec3(d8 * d4 / d6, vec3d1.y, d8 * d5 / d6);
++ this.setDeltaMovement(vec3d1);
+ Entity entity = this.getFirstPassenger();
+
+ if (entity instanceof Player) {
+- Vec3 vec32 = entity.getDeltaMovement();
+- double d9 = vec32.horizontalDistanceSqr();
++ Vec3 vec3d2 = entity.getDeltaMovement();
++ double d9 = vec3d2.horizontalDistanceSqr();
+ double d10 = this.getDeltaMovement().horizontalDistanceSqr();
+
+ if (d9 > 1.0E-4D && d10 < 0.01D) {
+- this.setDeltaMovement(this.getDeltaMovement().add(vec32.x * 0.1D, 0.0D, vec32.z * 0.1D));
++ this.setDeltaMovement(this.getDeltaMovement().add(vec3d2.x * 0.1D, 0.0D, vec3d2.z * 0.1D));
+ flag1 = false;
+ }
+ }
+@@ -491,10 +548,10 @@
+ }
+ }
+
+- d11 = (double) blockpos.getX() + 0.5D + (double) vec3i.getX() * 0.5D;
+- double d12 = (double) blockpos.getZ() + 0.5D + (double) vec3i.getZ() * 0.5D;
+- double d13 = (double) blockpos.getX() + 0.5D + (double) vec3i1.getX() * 0.5D;
+- double d14 = (double) blockpos.getZ() + 0.5D + (double) vec3i1.getZ() * 0.5D;
++ d11 = (double) pos.getX() + 0.5D + (double) baseblockposition.getX() * 0.5D;
++ double d12 = (double) pos.getZ() + 0.5D + (double) baseblockposition.getZ() * 0.5D;
++ double d13 = (double) pos.getX() + 0.5D + (double) baseblockposition1.getX() * 0.5D;
++ double d14 = (double) pos.getZ() + 0.5D + (double) baseblockposition1.getZ() * 0.5D;
+
+ d4 = d13 - d11;
+ d5 = d14 - d12;
+@@ -503,9 +560,9 @@
+ double d17;
+
+ if (d4 == 0.0D) {
+- d15 = d2 - (double) blockpos.getZ();
++ d15 = d2 - (double) pos.getZ();
+ } else if (d5 == 0.0D) {
+- d15 = d0 - (double) blockpos.getX();
++ d15 = d0 - (double) pos.getX();
+ } else {
+ d16 = d0 - d11;
+ d17 = d2 - d12;
+@@ -517,230 +574,233 @@
+ this.setPos(d0, d1, d2);
+ d16 = this.isVehicle() ? 0.75D : 1.0D;
+ d17 = this.getMaxSpeed();
+- vec31 = this.getDeltaMovement();
+- this.move(MoverType.SELF, new Vec3(Mth.clamp(d16 * vec31.x, -d17, d17), 0.0D, Mth.clamp(d16 * vec31.z, -d17, d17)));
+- if (vec3i.getY() != 0 && Mth.floor(this.getX()) - blockpos.getX() == vec3i.getX() && Mth.floor(this.getZ()) - blockpos.getZ() == vec3i.getZ()) {
+- this.setPos(this.getX(), this.getY() + (double) vec3i.getY(), this.getZ());
+- } else if (vec3i1.getY() != 0 && Mth.floor(this.getX()) - blockpos.getX() == vec3i1.getX() && Mth.floor(this.getZ()) - blockpos.getZ() == vec3i1.getZ()) {
+- this.setPos(this.getX(), this.getY() + (double) vec3i1.getY(), this.getZ());
++ vec3d1 = this.getDeltaMovement();
++ this.move(EnumMoveType.SELF, new Vec3(Mth.clamp(d16 * vec3d1.x, -d17, d17), 0.0D, Mth.clamp(d16 * vec3d1.z, -d17, d17)));
++ if (baseblockposition.getY() != 0 && Mth.floor(this.getX()) - pos.getX() == baseblockposition.getX() && Mth.floor(this.getZ()) - pos.getZ() == baseblockposition.getZ()) {
++ this.setPos(this.getX(), this.getY() + (double) baseblockposition.getY(), this.getZ());
++ } else if (baseblockposition1.getY() != 0 && Mth.floor(this.getX()) - pos.getX() == baseblockposition1.getX() && Mth.floor(this.getZ()) - pos.getZ() == baseblockposition1.getZ()) {
++ this.setPos(this.getX(), this.getY() + (double) baseblockposition1.getY(), this.getZ());
+ }
+
+ this.applyNaturalSlowdown();
+- Vec3 vec33 = this.getPos(this.getX(), this.getY(), this.getZ());
+- Vec3 vec34;
++ Vec3 vec3d3 = this.getPos(this.getX(), this.getY(), this.getZ());
++ Vec3 vec3d4;
+ double d18;
+
+- if (vec33 != null && vec3 != null) {
+- double d19 = (vec3.y - vec33.y) * 0.05D;
++ if (vec3d3 != null && vec3d != null) {
++ double d19 = (vec3d.y - vec3d3.y) * 0.05D;
+
+- vec34 = this.getDeltaMovement();
+- d18 = vec34.horizontalDistance();
++ vec3d4 = this.getDeltaMovement();
++ d18 = vec3d4.horizontalDistance();
+ if (d18 > 0.0D) {
+- this.setDeltaMovement(vec34.multiply((d18 + d19) / d18, 1.0D, (d18 + d19) / d18));
++ this.setDeltaMovement(vec3d4.multiply((d18 + d19) / d18, 1.0D, (d18 + d19) / d18));
+ }
+
+- this.setPos(this.getX(), vec33.y, this.getZ());
++ this.setPos(this.getX(), vec3d3.y, this.getZ());
+ }
+
+ int i = Mth.floor(this.getX());
+ int j = Mth.floor(this.getZ());
+
+- if (i != blockpos.getX() || j != blockpos.getZ()) {
+- vec34 = this.getDeltaMovement();
+- d18 = vec34.horizontalDistance();
+- this.setDeltaMovement(d18 * (double) (i - blockpos.getX()), vec34.y, d18 * (double) (j - blockpos.getZ()));
++ if (i != pos.getX() || j != pos.getZ()) {
++ vec3d4 = this.getDeltaMovement();
++ d18 = vec3d4.horizontalDistance();
++ this.setDeltaMovement(d18 * (double) (i - pos.getX()), vec3d4.y, d18 * (double) (j - pos.getZ()));
+ }
+
+ if (flag) {
+- vec34 = this.getDeltaMovement();
+- d18 = vec34.horizontalDistance();
++ vec3d4 = this.getDeltaMovement();
++ d18 = vec3d4.horizontalDistance();
+ if (d18 > 0.01D) {
+ double d20 = 0.06D;
+
+- this.setDeltaMovement(vec34.add(vec34.x / d18 * 0.06D, 0.0D, vec34.z / d18 * 0.06D));
++ this.setDeltaMovement(vec3d4.add(vec3d4.x / d18 * 0.06D, 0.0D, vec3d4.z / d18 * 0.06D));
+ } else {
+- Vec3 vec35 = this.getDeltaMovement();
+- double d21 = vec35.x;
+- double d22 = vec35.z;
++ Vec3 vec3d5 = this.getDeltaMovement();
++ double d21 = vec3d5.x;
++ double d22 = vec3d5.z;
+
+- if (railshape == RailShape.EAST_WEST) {
+- if (this.isRedstoneConductor(blockpos.west())) {
++ if (blockpropertytrackposition == RailShape.EAST_WEST) {
++ if (this.isRedstoneConductor(pos.west())) {
+ d21 = 0.02D;
+- } else if (this.isRedstoneConductor(blockpos.east())) {
++ } else if (this.isRedstoneConductor(pos.east())) {
+ d21 = -0.02D;
+ }
+ } else {
+- if (railshape != RailShape.NORTH_SOUTH) {
++ if (blockpropertytrackposition != RailShape.NORTH_SOUTH) {
+ return;
+ }
+
+- if (this.isRedstoneConductor(blockpos.north())) {
++ if (this.isRedstoneConductor(pos.north())) {
+ d22 = 0.02D;
+- } else if (this.isRedstoneConductor(blockpos.south())) {
++ } else if (this.isRedstoneConductor(pos.south())) {
+ d22 = -0.02D;
+ }
+ }
+
+- this.setDeltaMovement(d21, vec35.y, d22);
++ this.setDeltaMovement(d21, vec3d5.y, d22);
+ }
+ }
+
+ }
+
+ @Override
+- @Override
+ public boolean isOnRails() {
+ return this.onRails;
+ }
+
+- private boolean isRedstoneConductor(BlockPos blockpos) {
+- return this.level().getBlockState(blockpos).isRedstoneConductor(this.level(), blockpos);
++ private boolean isRedstoneConductor(BlockPos pos) {
++ return this.level().getBlockState(pos).isRedstoneConductor(this.level(), pos);
+ }
+
+ protected void applyNaturalSlowdown() {
+- double d0 = this.isVehicle() ? 0.997D : 0.96D;
+- Vec3 vec3 = this.getDeltaMovement();
++ double d0 = this.isVehicle() || !this.slowWhenEmpty ? 0.997D : 0.96D; // CraftBukkit - add !this.slowWhenEmpty
++ Vec3 vec3d = this.getDeltaMovement();
+
+- vec3 = vec3.multiply(d0, 0.0D, d0);
++ vec3d = vec3d.multiply(d0, 0.0D, d0);
+ if (this.isInWater()) {
+- vec3 = vec3.scale(0.949999988079071D);
++ vec3d = vec3d.scale(0.949999988079071D);
+ }
+
+- this.setDeltaMovement(vec3);
++ this.setDeltaMovement(vec3d);
+ }
+
+ @Nullable
+- public Vec3 getPosOffs(double d0, double d1, double d2, double d3) {
+- int i = Mth.floor(d0);
++ public Vec3 getPosOffs(double x, double d1, double y, double d3) {
++ int i = Mth.floor(x);
+ int j = Mth.floor(d1);
+- int k = Mth.floor(d2);
++ int k = Mth.floor(y);
+
+ if (this.level().getBlockState(new BlockPos(i, j - 1, k)).is(BlockTags.RAILS)) {
+ --j;
+ }
+
+- BlockState blockstate = this.level().getBlockState(new BlockPos(i, j, k));
++ IBlockData iblockdata = this.level().getBlockState(new BlockPos(i, j, k));
+
+- if (BaseRailBlock.isRail(blockstate)) {
+- RailShape railshape = (RailShape) blockstate.getValue(((BaseRailBlock) blockstate.getBlock()).getShapeProperty());
++ if (BaseRailBlock.isRail(iblockdata)) {
++ RailShape blockpropertytrackposition = (RailShape) iblockdata.getValue(((BaseRailBlock) iblockdata.getBlock()).getShapeProperty());
+
+ d1 = (double) j;
+- if (railshape.isAscending()) {
++ if (blockpropertytrackposition.isAscending()) {
+ d1 = (double) (j + 1);
+ }
+
+- Pair<Vec3i, Vec3i> pair = exits(railshape);
+- Vec3i vec3i = (Vec3i) pair.getFirst();
+- Vec3i vec3i1 = (Vec3i) pair.getSecond();
+- double d4 = (double) (vec3i1.getX() - vec3i.getX());
+- double d5 = (double) (vec3i1.getZ() - vec3i.getZ());
++ Pair<Vec3i, Vec3i> pair = exits(blockpropertytrackposition);
++ Vec3i baseblockposition = (Vec3i) pair.getFirst();
++ Vec3i baseblockposition1 = (Vec3i) pair.getSecond();
++ double d4 = (double) (baseblockposition1.getX() - baseblockposition.getX());
++ double d5 = (double) (baseblockposition1.getZ() - baseblockposition.getZ());
+ double d6 = Math.sqrt(d4 * d4 + d5 * d5);
+
+ d4 /= d6;
+ d5 /= d6;
+- d0 += d4 * d3;
+- d2 += d5 * d3;
+- if (vec3i.getY() != 0 && Mth.floor(d0) - i == vec3i.getX() && Mth.floor(d2) - k == vec3i.getZ()) {
+- d1 += (double) vec3i.getY();
+- } else if (vec3i1.getY() != 0 && Mth.floor(d0) - i == vec3i1.getX() && Mth.floor(d2) - k == vec3i1.getZ()) {
+- d1 += (double) vec3i1.getY();
++ x += d4 * d3;
++ y += d5 * d3;
++ if (baseblockposition.getY() != 0 && Mth.floor(x) - i == baseblockposition.getX() && Mth.floor(y) - k == baseblockposition.getZ()) {
++ d1 += (double) baseblockposition.getY();
++ } else if (baseblockposition1.getY() != 0 && Mth.floor(x) - i == baseblockposition1.getX() && Mth.floor(y) - k == baseblockposition1.getZ()) {
++ d1 += (double) baseblockposition1.getY();
+ }
+
+- return this.getPos(d0, d1, d2);
++ return this.getPos(x, d1, y);
+ } else {
+ return null;
+ }
+ }
+
+ @Nullable
+- public Vec3 getPos(double d0, double d1, double d2) {
+- int i = Mth.floor(d0);
++ public Vec3 getPos(double x, double d1, double y) {
++ int i = Mth.floor(x);
+ int j = Mth.floor(d1);
+- int k = Mth.floor(d2);
++ int k = Mth.floor(y);
+
+ if (this.level().getBlockState(new BlockPos(i, j - 1, k)).is(BlockTags.RAILS)) {
+ --j;
+ }
+
+- BlockState blockstate = this.level().getBlockState(new BlockPos(i, j, k));
++ IBlockData iblockdata = this.level().getBlockState(new BlockPos(i, j, k));
+
+- if (BaseRailBlock.isRail(blockstate)) {
+- RailShape railshape = (RailShape) blockstate.getValue(((BaseRailBlock) blockstate.getBlock()).getShapeProperty());
+- Pair<Vec3i, Vec3i> pair = exits(railshape);
+- Vec3i vec3i = (Vec3i) pair.getFirst();
+- Vec3i vec3i1 = (Vec3i) pair.getSecond();
+- double d3 = (double) i + 0.5D + (double) vec3i.getX() * 0.5D;
+- double d4 = (double) j + 0.0625D + (double) vec3i.getY() * 0.5D;
+- double d5 = (double) k + 0.5D + (double) vec3i.getZ() * 0.5D;
+- double d6 = (double) i + 0.5D + (double) vec3i1.getX() * 0.5D;
+- double d7 = (double) j + 0.0625D + (double) vec3i1.getY() * 0.5D;
+- double d8 = (double) k + 0.5D + (double) vec3i1.getZ() * 0.5D;
++ if (BaseRailBlock.isRail(iblockdata)) {
++ RailShape blockpropertytrackposition = (RailShape) iblockdata.getValue(((BaseRailBlock) iblockdata.getBlock()).getShapeProperty());
++ Pair<Vec3i, Vec3i> pair = exits(blockpropertytrackposition);
++ Vec3i baseblockposition = (Vec3i) pair.getFirst();
++ Vec3i baseblockposition1 = (Vec3i) pair.getSecond();
++ double d3 = (double) i + 0.5D + (double) baseblockposition.getX() * 0.5D;
++ double d4 = (double) j + 0.0625D + (double) baseblockposition.getY() * 0.5D;
++ double d5 = (double) k + 0.5D + (double) baseblockposition.getZ() * 0.5D;
++ double d6 = (double) i + 0.5D + (double) baseblockposition1.getX() * 0.5D;
++ double d7 = (double) j + 0.0625D + (double) baseblockposition1.getY() * 0.5D;
++ double d8 = (double) k + 0.5D + (double) baseblockposition1.getZ() * 0.5D;
+ double d9 = d6 - d3;
+ double d10 = (d7 - d4) * 2.0D;
+ double d11 = d8 - d5;
+ double d12;
+
+ if (d9 == 0.0D) {
+- d12 = d2 - (double) k;
++ d12 = y - (double) k;
+ } else if (d11 == 0.0D) {
+- d12 = d0 - (double) i;
++ d12 = x - (double) i;
+ } else {
+- double d13 = d0 - d3;
+- double d14 = d2 - d5;
++ double d13 = x - d3;
++ double d14 = y - d5;
+
+ d12 = (d13 * d9 + d14 * d11) * 2.0D;
+ }
+
+- d0 = d3 + d9 * d12;
++ x = d3 + d9 * d12;
+ d1 = d4 + d10 * d12;
+- d2 = d5 + d11 * d12;
++ y = d5 + d11 * d12;
+ if (d10 < 0.0D) {
+ ++d1;
+ } else if (d10 > 0.0D) {
+ d1 += 0.5D;
+ }
+
+- return new Vec3(d0, d1, d2);
++ return new Vec3(x, d1, y);
+ } else {
+ return null;
+ }
+ }
+
+ @Override
+- @Override
+ public AABB getBoundingBoxForCulling() {
+- AABB aabb = this.getBoundingBox();
++ AABB axisalignedbb = this.getBoundingBox();
+
+- return this.hasCustomDisplay() ? aabb.inflate((double) Math.abs(this.getDisplayOffset()) / 16.0D) : aabb;
++ return this.hasCustomDisplay() ? axisalignedbb.inflate((double) Math.abs(this.getDisplayOffset()) / 16.0D) : axisalignedbb;
+ }
+
+ @Override
+- @Override
+- protected void readAdditionalSaveData(CompoundTag compoundtag) {
+- if (compoundtag.getBoolean("CustomDisplayTile")) {
+- this.setDisplayBlockState(NbtUtils.readBlockState(this.level().holderLookup(Registries.BLOCK), compoundtag.getCompound("DisplayState")));
+- this.setDisplayOffset(compoundtag.getInt("DisplayOffset"));
++ protected void readAdditionalSaveData(CompoundTag compound) {
++ if (compound.getBoolean("CustomDisplayTile")) {
++ this.setDisplayBlockState(NbtUtils.readBlockState(this.level().holderLookup(Registries.BLOCK), compound.getCompound("DisplayState")));
++ this.setDisplayOffset(compound.getInt("DisplayOffset"));
+ }
+
+ }
+
+ @Override
+- @Override
+- protected void addAdditionalSaveData(CompoundTag compoundtag) {
++ protected void addAdditionalSaveData(CompoundTag compound) {
+ if (this.hasCustomDisplay()) {
+- compoundtag.putBoolean("CustomDisplayTile", true);
+- compoundtag.put("DisplayState", NbtUtils.writeBlockState(this.getDisplayBlockState()));
+- compoundtag.putInt("DisplayOffset", this.getDisplayOffset());
++ compound.putBoolean("CustomDisplayTile", true);
++ compound.put("DisplayState", NbtUtils.writeBlockState(this.getDisplayBlockState()));
++ compound.putInt("DisplayOffset", this.getDisplayOffset());
+ }
+
+ }
+
+ @Override
+- @Override
+ public void push(Entity entity) {
+ if (!this.level().isClientSide) {
+ if (!entity.noPhysics && !this.noPhysics) {
+ if (!this.hasPassenger(entity)) {
++ // CraftBukkit start
++ VehicleEntityCollisionEvent collisionEvent = new VehicleEntityCollisionEvent((Vehicle) this.getBukkitEntity(), entity.getBukkitEntity());
++ this.level().getCraftServer().getPluginManager().callEvent(collisionEvent);
++
++ if (collisionEvent.isCancelled()) {
++ return;
++ }
++ // CraftBukkit end
+ double d0 = entity.getX() - this.getX();
+ double d1 = entity.getZ() - this.getZ();
+ double d2 = d0 * d0 + d1 * d1;
+@@ -764,32 +824,32 @@
+ if (entity instanceof AbstractMinecart) {
+ double d4 = entity.getX() - this.getX();
+ double d5 = entity.getZ() - this.getZ();
+- Vec3 vec3 = (new Vec3(d4, 0.0D, d5)).normalize();
+- Vec3 vec31 = (new Vec3((double) Mth.cos(this.getYRot() * 0.017453292F), 0.0D, (double) Mth.sin(this.getYRot() * 0.017453292F))).normalize();
+- double d6 = Math.abs(vec3.dot(vec31));
++ Vec3 vec3d = (new Vec3(d4, 0.0D, d5)).normalize();
++ Vec3 vec3d1 = (new Vec3((double) Mth.cos(this.getYRot() * 0.017453292F), 0.0D, (double) Mth.sin(this.getYRot() * 0.017453292F))).normalize();
++ double d6 = Math.abs(vec3d.dot(vec3d1));
+
+ if (d6 < 0.800000011920929D) {
+ return;
+ }
+
+- Vec3 vec32 = this.getDeltaMovement();
+- Vec3 vec33 = entity.getDeltaMovement();
++ Vec3 vec3d2 = this.getDeltaMovement();
++ Vec3 vec3d3 = entity.getDeltaMovement();
+
+- if (((AbstractMinecart) entity).getMinecartType() == AbstractMinecart.Type.FURNACE && this.getMinecartType() != AbstractMinecart.Type.FURNACE) {
+- this.setDeltaMovement(vec32.multiply(0.2D, 1.0D, 0.2D));
+- this.push(vec33.x - d0, 0.0D, vec33.z - d1);
+- entity.setDeltaMovement(vec33.multiply(0.95D, 1.0D, 0.95D));
+- } else if (((AbstractMinecart) entity).getMinecartType() != AbstractMinecart.Type.FURNACE && this.getMinecartType() == AbstractMinecart.Type.FURNACE) {
+- entity.setDeltaMovement(vec33.multiply(0.2D, 1.0D, 0.2D));
+- entity.push(vec32.x + d0, 0.0D, vec32.z + d1);
+- this.setDeltaMovement(vec32.multiply(0.95D, 1.0D, 0.95D));
++ if (((AbstractMinecart) entity).getMinecartType() == AbstractMinecart.EnumMinecartType.FURNACE && this.getMinecartType() != AbstractMinecart.EnumMinecartType.FURNACE) {
++ this.setDeltaMovement(vec3d2.multiply(0.2D, 1.0D, 0.2D));
++ this.push(vec3d3.x - d0, 0.0D, vec3d3.z - d1);
++ entity.setDeltaMovement(vec3d3.multiply(0.95D, 1.0D, 0.95D));
++ } else if (((AbstractMinecart) entity).getMinecartType() != AbstractMinecart.EnumMinecartType.FURNACE && this.getMinecartType() == AbstractMinecart.EnumMinecartType.FURNACE) {
++ entity.setDeltaMovement(vec3d3.multiply(0.2D, 1.0D, 0.2D));
++ entity.push(vec3d2.x + d0, 0.0D, vec3d2.z + d1);
++ this.setDeltaMovement(vec3d2.multiply(0.95D, 1.0D, 0.95D));
+ } else {
+- double d7 = (vec33.x + vec32.x) / 2.0D;
+- double d8 = (vec33.z + vec32.z) / 2.0D;
++ double d7 = (vec3d3.x + vec3d2.x) / 2.0D;
++ double d8 = (vec3d3.z + vec3d2.z) / 2.0D;
+
+- this.setDeltaMovement(vec32.multiply(0.2D, 1.0D, 0.2D));
++ this.setDeltaMovement(vec3d2.multiply(0.2D, 1.0D, 0.2D));
+ this.push(d7 - d0, 0.0D, d8 - d1);
+- entity.setDeltaMovement(vec33.multiply(0.2D, 1.0D, 0.2D));
++ entity.setDeltaMovement(vec3d3.multiply(0.2D, 1.0D, 0.2D));
+ entity.push(d7 + d0, 0.0D, d8 + d1);
+ }
+ } else {
+@@ -804,7 +864,6 @@
+ }
+
+ @Override
+- @Override
+ public void lerpTo(double d0, double d1, double d2, float f, float f1, int i) {
+ this.lerpX = d0;
+ this.lerpY = d1;
+@@ -816,49 +875,43 @@
+ }
+
+ @Override
+- @Override
+ public double lerpTargetX() {
+ return this.lerpSteps > 0 ? this.lerpX : this.getX();
+ }
+
+ @Override
+- @Override
+ public double lerpTargetY() {
+ return this.lerpSteps > 0 ? this.lerpY : this.getY();
+ }
+
+ @Override
+- @Override
+ public double lerpTargetZ() {
+ return this.lerpSteps > 0 ? this.lerpZ : this.getZ();
+ }
+
+ @Override
+- @Override
+ public float lerpTargetXRot() {
+ return this.lerpSteps > 0 ? (float) this.lerpXRot : this.getXRot();
+ }
+
+ @Override
+- @Override
+ public float lerpTargetYRot() {
+ return this.lerpSteps > 0 ? (float) this.lerpYRot : this.getYRot();
+ }
+
+ @Override
+- @Override
+- public void lerpMotion(double d0, double d1, double d2) {
+- this.targetDeltaMovement = new Vec3(d0, d1, d2);
++ public void lerpMotion(double x, double d1, double y) {
++ this.targetDeltaMovement = new Vec3(x, d1, y);
+ this.setDeltaMovement(this.targetDeltaMovement);
+ }
+
+- public abstract AbstractMinecart.Type getMinecartType();
++ public abstract AbstractMinecart.EnumMinecartType getMinecartType();
+
+- public BlockState getDisplayBlockState() {
++ public IBlockData getDisplayBlockState() {
+ return !this.hasCustomDisplay() ? this.getDefaultDisplayBlockState() : Block.stateById((Integer) this.getEntityData().get(AbstractMinecart.DATA_ID_DISPLAY_BLOCK));
+ }
+
+- public BlockState getDefaultDisplayBlockState() {
++ public IBlockData getDefaultDisplayBlockState() {
+ return Blocks.AIR.defaultBlockState();
+ }
+
+@@ -870,13 +923,13 @@
+ return 6;
+ }
+
+- public void setDisplayBlockState(BlockState blockstate) {
+- this.getEntityData().set(AbstractMinecart.DATA_ID_DISPLAY_BLOCK, Block.getId(blockstate));
++ public void setDisplayBlockState(IBlockData displayState) {
++ this.getEntityData().set(AbstractMinecart.DATA_ID_DISPLAY_BLOCK, Block.getId(displayState));
+ this.setCustomDisplay(true);
+ }
+
+- public void setDisplayOffset(int i) {
+- this.getEntityData().set(AbstractMinecart.DATA_ID_DISPLAY_OFFSET, i);
++ public void setDisplayOffset(int displayOffset) {
++ this.getEntityData().set(AbstractMinecart.DATA_ID_DISPLAY_OFFSET, displayOffset);
+ this.setCustomDisplay(true);
+ }
+
+@@ -884,12 +937,11 @@
+ return (Boolean) this.getEntityData().get(AbstractMinecart.DATA_ID_CUSTOM_DISPLAY);
+ }
+
+- public void setCustomDisplay(boolean flag) {
+- this.getEntityData().set(AbstractMinecart.DATA_ID_CUSTOM_DISPLAY, flag);
++ public void setCustomDisplay(boolean customDisplay) {
++ this.getEntityData().set(AbstractMinecart.DATA_ID_CUSTOM_DISPLAY, customDisplay);
+ }
+
+ @Override
+- @Override
+ public ItemStack getPickResult() {
+ Item item;
+
+@@ -917,10 +969,32 @@
+ return new ItemStack(item);
+ }
+
+- public static enum Type {
++ public static enum EnumMinecartType {
+
+ RIDEABLE, CHEST, FURNACE, TNT, SPAWNER, HOPPER, COMMAND_BLOCK;
+
+- private Type() {}
++ private EnumMinecartType() {}
+ }
++
++ // CraftBukkit start - Methods for getting and setting flying and derailed velocity modifiers
++ public Vector getFlyingVelocityMod() {
++ return new Vector(flyingX, flyingY, flyingZ);
++ }
++
++ public void setFlyingVelocityMod(Vector flying) {
++ flyingX = flying.getX();
++ flyingY = flying.getY();
++ flyingZ = flying.getZ();
++ }
++
++ public Vector getDerailedVelocityMod() {
++ return new Vector(derailedX, derailedY, derailedZ);
++ }
++
++ public void setDerailedVelocityMod(Vector derailed) {
++ derailedX = derailed.getX();
++ derailedY = derailed.getY();
++ derailedZ = derailed.getZ();
++ }
++ // CraftBukkit end
+ }