--- a/net/minecraft/entity/item/minecart/AbstractMinecartEntity.java
+++ b/net/minecraft/entity/item/minecart/AbstractMinecartEntity.java
@@ -47,7 +47,7 @@
 import net.minecraftforge.api.distmarker.Dist;
 import net.minecraftforge.api.distmarker.OnlyIn;
 
-public abstract class AbstractMinecartEntity extends Entity {
+public abstract class AbstractMinecartEntity extends Entity implements net.minecraftforge.common.extensions.IForgeEntityMinecart {
    private static final DataParameter<Integer> field_184265_a = EntityDataManager.func_187226_a(AbstractMinecartEntity.class, DataSerializers.field_187192_b);
    private static final DataParameter<Integer> field_184266_b = EntityDataManager.func_187226_a(AbstractMinecartEntity.class, DataSerializers.field_187192_b);
    private static final DataParameter<Float> field_184267_c = EntityDataManager.func_187226_a(AbstractMinecartEntity.class, DataSerializers.field_187193_c);
@@ -88,6 +88,7 @@
    private double field_70507_ar;
    @OnlyIn(Dist.CLIENT)
    private double field_70506_as;
+   private boolean canBePushed = true;
 
    protected AbstractMinecartEntity(EntityType<?> p_i48538_1_, World p_i48538_2_) {
       super(p_i48538_1_, p_i48538_2_);
@@ -134,11 +135,12 @@
 
    @Nullable
    public AxisAlignedBB func_70114_g(Entity p_70114_1_) {
+      if (getCollisionHandler() != null) return getCollisionHandler().getCollisionBox(this, p_70114_1_);
       return p_70114_1_.func_70104_M() ? p_70114_1_.func_174813_aQ() : null;
    }
 
    public boolean func_70104_M() {
-      return true;
+      return canBePushed;
    }
 
    public double func_70042_X() {
@@ -304,9 +306,9 @@
 
          BlockPos blockpos = new BlockPos(i, j, k);
          BlockState blockstate = this.field_70170_p.func_180495_p(blockpos);
-         if (AbstractRailBlock.func_208487_j(blockstate)) {
+         if (canUseRail() && AbstractRailBlock.func_208487_j(blockstate)) {
             this.func_180460_a(blockpos, blockstate);
-            if (blockstate.func_203425_a(Blocks.field_150408_cc)) {
+            if (blockstate.func_177230_c() instanceof PoweredRailBlock && ((PoweredRailBlock) blockstate.func_177230_c()).isActivatorRail()) {
                this.func_96095_a(i, j, k, blockstate.func_177229_b(PoweredRailBlock.field_176569_M));
             }
          } else {
@@ -331,8 +333,11 @@
          }
 
          this.func_70101_b(this.field_70177_z, this.field_70125_A);
-         if (this.func_184264_v() == AbstractMinecartEntity.Type.RIDEABLE && func_213296_b(this.func_213322_ci()) > 0.01D) {
-            List<Entity> list = this.field_70170_p.func_175674_a(this, this.func_174813_aQ().func_72314_b((double)0.2F, 0.0D, (double)0.2F), EntityPredicates.func_200823_a(this));
+         AxisAlignedBB box;
+         if (getCollisionHandler() != null) box = getCollisionHandler().getMinecartCollisionBox(this);
+         else                               box = this.func_174813_aQ().func_72314_b(0.2F, 0.0D, 0.2F);
+         if (canBeRidden() && func_213296_b(this.func_213322_ci()) > 0.01D) {
+            List<Entity> list = this.field_70170_p.func_175674_a(this, box, EntityPredicates.func_200823_a(this));
             if (!list.isEmpty()) {
                for(int l = 0; l < list.size(); ++l) {
                   Entity entity1 = list.get(l);
@@ -344,7 +349,7 @@
                }
             }
          } else {
-            for(Entity entity : this.field_70170_p.func_72839_b(this, this.func_174813_aQ().func_72314_b((double)0.2F, 0.0D, (double)0.2F))) {
+            for(Entity entity : this.field_70170_p.func_72839_b(this, box)) {
                if (!this.func_184196_w(entity) && entity.func_70104_M() && entity instanceof AbstractMinecartEntity) {
                   entity.func_70108_f(this);
                }
@@ -352,6 +357,7 @@
          }
 
          this.func_233566_aG_();
+         //net.minecraftforge.common.MinecraftForge.EVENT_BUS.post(new net.minecraftforge.event.entity.minecart.MinecartUpdateEvent(this, this.getCurrentRailPosition()));
       }
    }
 
@@ -363,16 +369,23 @@
    }
 
    protected void func_180459_n() {
-      double d0 = this.func_174898_m();
+      double d0 = field_70122_E ? this.func_174898_m() : getMaxSpeedAirLateral();
       Vector3d vector3d = this.func_213322_ci();
       this.func_213293_j(MathHelper.func_151237_a(vector3d.field_72450_a, -d0, d0), vector3d.field_72448_b, MathHelper.func_151237_a(vector3d.field_72449_c, -d0, d0));
       if (this.field_70122_E) {
          this.func_213317_d(this.func_213322_ci().func_186678_a(0.5D));
       }
 
+      if (getMaxSpeedAirVertical() > 0 && func_213322_ci().field_72448_b > getMaxSpeedAirVertical()) {
+          if(Math.abs(func_213322_ci().field_72450_a) < 0.3f && Math.abs(func_213322_ci().field_72449_c) < 0.3f)
+              func_213317_d(new Vector3d(func_213322_ci().field_72450_a, 0.15f, func_213322_ci().field_72449_c));
+          else
+              func_213317_d(new Vector3d(func_213322_ci().field_72450_a, getMaxSpeedAirVertical(), func_213322_ci().field_72449_c));
+      }
+
       this.func_213315_a(MoverType.SELF, this.func_213322_ci());
       if (!this.field_70122_E) {
-         this.func_213317_d(this.func_213322_ci().func_186678_a(0.95D));
+         this.func_213317_d(this.func_213322_ci().func_186678_a(getDragAir()));
       }
 
    }
@@ -387,29 +400,29 @@
       boolean flag = false;
       boolean flag1 = false;
       AbstractRailBlock abstractrailblock = (AbstractRailBlock)p_180460_2_.func_177230_c();
-      if (abstractrailblock == Blocks.field_196552_aC) {
+      if (abstractrailblock instanceof PoweredRailBlock && !((PoweredRailBlock) abstractrailblock).isActivatorRail()) {
          flag = p_180460_2_.func_177229_b(PoweredRailBlock.field_176569_M);
          flag1 = !flag;
       }
 
       double d3 = 0.0078125D;
       Vector3d vector3d1 = this.func_213322_ci();
-      RailShape railshape = p_180460_2_.func_177229_b(abstractrailblock.func_176560_l());
+      RailShape railshape = ((AbstractRailBlock)p_180460_2_.func_177230_c()).getRailDirection(p_180460_2_, this.field_70170_p, p_180460_1_, this);
       switch(railshape) {
       case ASCENDING_EAST:
-         this.func_213317_d(vector3d1.func_72441_c(-0.0078125D, 0.0D, 0.0D));
+         this.func_213317_d(vector3d1.func_72441_c(-1 * getSlopeAdjustment(), 0.0D, 0.0D));
          ++d1;
          break;
       case ASCENDING_WEST:
-         this.func_213317_d(vector3d1.func_72441_c(0.0078125D, 0.0D, 0.0D));
+         this.func_213317_d(vector3d1.func_72441_c(getSlopeAdjustment(), 0.0D, 0.0D));
          ++d1;
          break;
       case ASCENDING_NORTH:
-         this.func_213317_d(vector3d1.func_72441_c(0.0D, 0.0D, 0.0078125D));
+         this.func_213317_d(vector3d1.func_72441_c(0.0D, 0.0D, getSlopeAdjustment()));
          ++d1;
          break;
       case ASCENDING_SOUTH:
-         this.func_213317_d(vector3d1.func_72441_c(0.0D, 0.0D, -0.0078125D));
+         this.func_213317_d(vector3d1.func_72441_c(0.0D, 0.0D, -1 * getSlopeAdjustment()));
          ++d1;
       }
 
@@ -440,7 +453,7 @@
          }
       }
 
-      if (flag1) {
+      if (flag1 && shouldDoRailFunctions()) {
          double d22 = Math.sqrt(func_213296_b(this.func_213322_ci()));
          if (d22 < 0.03D) {
             this.func_213317_d(Vector3d.field_186680_a);
@@ -469,10 +482,7 @@
       d0 = d23 + d4 * d14;
       d2 = d10 + d5 * d14;
       this.func_70107_b(d0, d1, d2);
-      double d24 = this.func_184207_aI() ? 0.75D : 1.0D;
-      double d25 = this.func_174898_m();
-      vector3d1 = this.func_213322_ci();
-      this.func_213315_a(MoverType.SELF, new Vector3d(MathHelper.func_151237_a(d24 * vector3d1.field_72450_a, -d25, d25), 0.0D, MathHelper.func_151237_a(d24 * vector3d1.field_72449_c, -d25, d25)));
+      this.moveMinecartOnRail(p_180460_1_);
       if (vector3i.func_177956_o() != 0 && MathHelper.func_76128_c(this.func_226277_ct_()) - p_180460_1_.func_177958_n() == vector3i.func_177958_n() && MathHelper.func_76128_c(this.func_226281_cx_()) - p_180460_1_.func_177952_p() == vector3i.func_177952_p()) {
          this.func_70107_b(this.func_226277_ct_(), this.func_226278_cu_() + (double)vector3i.func_177956_o(), this.func_226281_cx_());
       } else if (vector3i1.func_177956_o() != 0 && MathHelper.func_76128_c(this.func_226277_ct_()) - p_180460_1_.func_177958_n() == vector3i1.func_177958_n() && MathHelper.func_76128_c(this.func_226281_cx_()) - p_180460_1_.func_177952_p() == vector3i1.func_177952_p()) {
@@ -500,7 +510,10 @@
          this.func_213293_j(d26 * (double)(j - p_180460_1_.func_177958_n()), vector3d5.field_72448_b, d26 * (double)(i - p_180460_1_.func_177952_p()));
       }
 
-      if (flag) {
+      if (shouldDoRailFunctions())
+          ((AbstractRailBlock)p_180460_2_.func_177230_c()).onMinecartPass(p_180460_2_, field_70170_p, p_180460_1_, this);
+
+      if (flag && shouldDoRailFunctions()) {
          Vector3d vector3d6 = this.func_213322_ci();
          double d27 = Math.sqrt(func_213296_b(vector3d6));
          if (d27 > 0.01D) {
@@ -555,7 +568,7 @@
 
       BlockState blockstate = this.field_70170_p.func_180495_p(new BlockPos(i, j, k));
       if (AbstractRailBlock.func_208487_j(blockstate)) {
-         RailShape railshape = blockstate.func_177229_b(((AbstractRailBlock)blockstate.func_177230_c()).func_176560_l());
+         RailShape railshape = ((AbstractRailBlock)blockstate.func_177230_c()).getRailDirection(blockstate, this.field_70170_p, new BlockPos(i, j, k), this);
          p_70495_3_ = (double)j;
          if (railshape.func_208092_c()) {
             p_70495_3_ = (double)(j + 1);
@@ -594,7 +607,7 @@
 
       BlockState blockstate = this.field_70170_p.func_180495_p(new BlockPos(i, j, k));
       if (AbstractRailBlock.func_208487_j(blockstate)) {
-         RailShape railshape = blockstate.func_177229_b(((AbstractRailBlock)blockstate.func_177230_c()).func_176560_l());
+         RailShape railshape = ((AbstractRailBlock)blockstate.func_177230_c()).getRailDirection(blockstate, this.field_70170_p, new BlockPos(i, j, k), this);
          Pair<Vector3i, Vector3i> pair = func_226573_a_(railshape);
          Vector3i vector3i = pair.getFirst();
          Vector3i vector3i1 = pair.getSecond();
@@ -657,6 +670,11 @@
    }
 
    public void func_70108_f(Entity p_70108_1_) {
+      //net.minecraftforge.common.MinecraftForge.EVENT_BUS.post(new net.minecraftforge.event.entity.minecart.MinecartCollisionEvent(this, entityIn));
+      if (getCollisionHandler() != null) {
+         getCollisionHandler().onEntityCollision(this, p_70108_1_);
+         return;
+      }
       if (!this.field_70170_p.field_72995_K) {
          if (!p_70108_1_.field_70145_X && !this.field_70145_X) {
             if (!this.func_184196_w(p_70108_1_)) {
@@ -692,11 +710,11 @@
 
                      Vector3d vector3d2 = this.func_213322_ci();
                      Vector3d vector3d3 = p_70108_1_.func_213322_ci();
-                     if (((AbstractMinecartEntity)p_70108_1_).func_184264_v() == AbstractMinecartEntity.Type.FURNACE && this.func_184264_v() != AbstractMinecartEntity.Type.FURNACE) {
+                     if (((AbstractMinecartEntity)p_70108_1_).isPoweredCart() && !this.isPoweredCart()) {
                         this.func_213317_d(vector3d2.func_216372_d(0.2D, 1.0D, 0.2D));
                         this.func_70024_g(vector3d3.field_72450_a - d0, 0.0D, vector3d3.field_72449_c - d1);
                         p_70108_1_.func_213317_d(vector3d3.func_216372_d(0.95D, 1.0D, 0.95D));
-                     } else if (((AbstractMinecartEntity)p_70108_1_).func_184264_v() != AbstractMinecartEntity.Type.FURNACE && this.func_184264_v() == AbstractMinecartEntity.Type.FURNACE) {
+                     } else if (!((AbstractMinecartEntity)p_70108_1_).isPoweredCart() && this.isPoweredCart()) {
                         p_70108_1_.func_213317_d(vector3d3.func_216372_d(0.2D, 1.0D, 0.2D));
                         p_70108_1_.func_70024_g(vector3d2.field_72450_a + d0, 0.0D, vector3d2.field_72449_c + d1);
                         this.func_213317_d(vector3d2.func_216372_d(0.95D, 1.0D, 0.95D));
@@ -802,6 +820,40 @@
       return new SSpawnObjectPacket(this);
    }
 
+   private boolean canUseRail = true;
+   @Override public boolean canUseRail() { return canUseRail; }
+   @Override public void setCanUseRail(boolean value) { this.canUseRail = value; }
+   private float currentSpeedOnRail;
+   @Override public float getCurrentCartSpeedCapOnRail() { return currentSpeedOnRail; }
+   @Override public void setCurrentCartSpeedCapOnRail(float value) { currentSpeedOnRail = Math.min(value, getMaxCartSpeedOnRail()); }
+   private float maxSpeedAirLateral = DEFAULT_MAX_SPEED_AIR_LATERAL;
+   @Override public float getMaxSpeedAirLateral() { return maxSpeedAirLateral; }
+   @Override public void setMaxSpeedAirLateral(float value) { maxSpeedAirLateral = value; }
+   private float maxSpeedAirVertical = DEFAULT_MAX_SPEED_AIR_VERTICAL;
+   @Override public float getMaxSpeedAirVertical() { return maxSpeedAirVertical; }
+   @Override public void setMaxSpeedAirVertical(float value) { maxSpeedAirVertical = value; }
+   private double dragAir = DEFAULT_AIR_DRAG;
+   @Override public double getDragAir() { return dragAir; }
+   @Override public void setDragAir(double value) { dragAir = value; }
+   @Override
+   public double getMaxSpeedWithRail() { //Non-default because getMaximumSpeed is protected
+      if (!canUseRail()) return func_174898_m();
+      BlockPos pos = this.getCurrentRailPosition();
+      BlockState state = getMinecart().field_70170_p.func_180495_p(pos);
+      if (!state.func_235714_a_(BlockTags.field_203437_y)) return func_174898_m();
+
+      float railMaxSpeed = ((AbstractRailBlock)state.func_177230_c()).getRailMaxSpeed(state, getMinecart().field_70170_p, pos, getMinecart());
+      return Math.min(railMaxSpeed, getCurrentCartSpeedCapOnRail());
+   }
+   @Override
+   public void moveMinecartOnRail(BlockPos pos) { //Non-default because getMaximumSpeed is protected
+      AbstractMinecartEntity mc = getMinecart();
+      double d24 = mc.func_184207_aI() ? 0.75D : 1.0D;
+      double d25 = mc.getMaxSpeedWithRail();
+      Vector3d vec3d1 = mc.func_213322_ci();
+      mc.func_213315_a(MoverType.SELF, new Vector3d(MathHelper.func_151237_a(d24 * vec3d1.field_72450_a, -d25, d25), 0.0D, MathHelper.func_151237_a(d24 * vec3d1.field_72449_c, -d25, d25)));
+   }
+
    public static enum Type {
       RIDEABLE,
       CHEST,
