--- ../src-base/minecraft/net/minecraft/entity/item/EntityMinecart.java
+++ ../src-work/minecraft/net/minecraft/entity/item/EntityMinecart.java
@@ -52,6 +52,20 @@
     private double field_70506_as;
     private static final String __OBFID = "CL_00001670";
 
+    /* Forge: Minecart Compatibility Layer Integration. */
+    public static float defaultMaxSpeedAirLateral = 0.4f;
+    public static float defaultMaxSpeedAirVertical = -1f;
+    public static double defaultDragAir = 0.94999998807907104D;
+    protected boolean canUseRail = true;
+    protected boolean canBePushed = true;
+    private static net.minecraftforge.common.IMinecartCollisionHandler collisionHandler = null;
+
+    /* Instance versions of the above physics properties */
+    private float currentSpeedRail = getMaxCartSpeedOnRail();
+    protected float maxSpeedAirLateral = defaultMaxSpeedAirLateral;
+    protected float maxSpeedAirVertical = defaultMaxSpeedAirVertical;
+    protected double dragAir = defaultDragAir;
+
     public EntityMinecart(World p_i1712_1_)
     {
         super(p_i1712_1_);
@@ -97,17 +111,19 @@
 
     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 AxisAlignedBB func_70046_E()
     {
+        if (getCollisionHandler() != null) return getCollisionHandler().getBoundingBox(this);
         return null;
     }
 
     public boolean func_70104_M()
     {
-        return true;
+        return canBePushed;
     }
 
     public EntityMinecart(World p_i1713_1_, double p_i1713_2_, double p_i1713_4_, double p_i1713_6_)
@@ -309,7 +325,7 @@
             BlockPos blockpos = new BlockPos(j, i, k);
             IBlockState iblockstate = this.field_70170_p.func_180495_p(blockpos);
 
-            if (BlockRailBase.func_176563_d(iblockstate))
+            if (canUseRail() && BlockRailBase.func_176563_d(iblockstate))
             {
                 this.func_180460_a(blockpos, iblockstate);
 
@@ -347,7 +363,10 @@
             }
 
             this.func_70101_b(this.field_70177_z, this.field_70125_A);
-            Iterator iterator = this.field_70170_p.func_72839_b(this, this.func_174813_aQ().func_72314_b(0.20000000298023224D, 0.0D, 0.20000000298023224D)).iterator();
+            AxisAlignedBB box;
+            if (getCollisionHandler() != null) box = this.getCollisionHandler().getMinecartCollisionBox(this);
+            else                               box = this.func_174813_aQ().func_72314_b(0.20000000298023224D, 0.0D, 0.20000000298023224D);
+            Iterator iterator = this.field_70170_p.func_72839_b(this, box).iterator();
 
             while (iterator.hasNext())
             {
@@ -370,6 +389,7 @@
             }
 
             this.func_70072_I();
+            net.minecraftforge.common.MinecraftForge.EVENT_BUS.post(new net.minecraftforge.event.entity.minecart.MinecartUpdateEvent(this, this.getCurrentRailPosition()));
         }
     }
 
@@ -382,10 +402,21 @@
 
     protected void func_180459_n()
     {
-        double d0 = this.func_174898_m();
+        double d0 = field_70122_E ? this.func_174898_m() : getMaxSpeedAirLateral();
         this.field_70159_w = MathHelper.func_151237_a(this.field_70159_w, -d0, d0);
         this.field_70179_y = MathHelper.func_151237_a(this.field_70179_y, -d0, d0);
 
+        double moveY = field_70181_x;
+        if(getMaxSpeedAirVertical() > 0 && field_70181_x > getMaxSpeedAirVertical())
+        {
+            moveY = getMaxSpeedAirVertical();
+            if(Math.abs(field_70159_w) < 0.3f && Math.abs(field_70179_y) < 0.3f)
+            {
+                moveY = 0.15f;
+                field_70181_x = moveY;
+            }
+        }
+
         if (this.field_70122_E)
         {
             this.field_70159_w *= 0.5D;
@@ -393,13 +424,13 @@
             this.field_70179_y *= 0.5D;
         }
 
-        this.func_70091_d(this.field_70159_w, this.field_70181_x, this.field_70179_y);
+        this.func_70091_d(this.field_70159_w, moveY, this.field_70179_y);
 
         if (!this.field_70122_E)
         {
-            this.field_70159_w *= 0.949999988079071D;
-            this.field_70181_x *= 0.949999988079071D;
-            this.field_70179_y *= 0.949999988079071D;
+            this.field_70159_w *= getDragAir();
+            this.field_70181_x *= getDragAir();
+            this.field_70179_y *= getDragAir();
         }
     }
 
@@ -418,25 +449,25 @@
             flag1 = !flag;
         }
 
-        double d0 = 0.0078125D;
+        double slopeAdjustment = getSlopeAdjustment();
         BlockRailBase.EnumRailDirection enumraildirection = (BlockRailBase.EnumRailDirection)p_180460_2_.func_177229_b(blockrailbase.func_176560_l());
 
         switch (EntityMinecart.SwitchEnumMinecartType.field_180036_b[enumraildirection.ordinal()])
         {
             case 1:
-                this.field_70159_w -= 0.0078125D;
+                this.field_70159_w -= slopeAdjustment;
                 ++this.field_70163_u;
                 break;
             case 2:
-                this.field_70159_w += 0.0078125D;
+                this.field_70159_w += slopeAdjustment;
                 ++this.field_70163_u;
                 break;
             case 3:
-                this.field_70179_y += 0.0078125D;
+                this.field_70179_y += slopeAdjustment;
                 ++this.field_70163_u;
                 break;
             case 4:
-                this.field_70179_y -= 0.0078125D;
+                this.field_70179_y -= slopeAdjustment;
                 ++this.field_70163_u;
         }
 
@@ -485,7 +516,7 @@
             }
         }
 
-        if (flag1)
+        if (flag1 && shouldDoRailFunctions())
         {
             d6 = Math.sqrt(this.field_70159_w * this.field_70159_w + this.field_70179_y * this.field_70179_y);
 
@@ -533,20 +564,8 @@
         this.field_70165_t = d7 + d1 * d6;
         this.field_70161_v = d8 + d2 * d6;
         this.func_70107_b(this.field_70165_t, this.field_70163_u, this.field_70161_v);
-        d11 = this.field_70159_w;
-        d12 = this.field_70179_y;
+        this.moveMinecartOnRail(p_180460_1_);
 
-        if (this.field_70153_n != null)
-        {
-            d11 *= 0.75D;
-            d12 *= 0.75D;
-        }
-
-        double d13 = this.func_174898_m();
-        d11 = MathHelper.func_151237_a(d11, -d13, d13);
-        d12 = MathHelper.func_151237_a(d12, -d13, d13);
-        this.func_70091_d(d11, 0.0D, d12);
-
         if (aint[0][1] != 0 && MathHelper.func_76128_c(this.field_70165_t) - p_180460_1_.func_177958_n() == aint[0][0] && MathHelper.func_76128_c(this.field_70161_v) - p_180460_1_.func_177952_p() == aint[0][2])
         {
             this.func_70107_b(this.field_70165_t, this.field_70163_u + (double)aint[0][1], this.field_70161_v);
@@ -583,8 +602,14 @@
             this.field_70179_y = d5 * (double)(i - p_180460_1_.func_177952_p());
         }
 
-        if (flag)
+
+        if(shouldDoRailFunctions())
         {
+            ((BlockRailBase)p_180460_2_.func_177230_c()).onMinecartPass(field_70170_p, this, p_180460_1_);
+        }
+
+        if (flag && shouldDoRailFunctions())
+        {
             double d15 = Math.sqrt(this.field_70159_w * this.field_70159_w + this.field_70179_y * this.field_70179_y);
 
             if (d15 > 0.01D)
@@ -824,13 +849,20 @@
 
     public void func_70108_f(Entity p_70108_1_)
     {
+
+        net.minecraftforge.common.MinecraftForge.EVENT_BUS.post(new net.minecraftforge.event.entity.minecart.MinecartCollisionEvent(this, p_70108_1_));
+        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 (p_70108_1_ != this.field_70153_n)
                 {
-                    if (p_70108_1_ instanceof EntityLivingBase && !(p_70108_1_ instanceof EntityPlayer) && !(p_70108_1_ instanceof EntityIronGolem) && this.func_180456_s() == EntityMinecart.EnumMinecartType.RIDEABLE && this.field_70159_w * this.field_70159_w + this.field_70179_y * this.field_70179_y > 0.01D && this.field_70153_n == null && p_70108_1_.field_70154_o == null)
+                    if (p_70108_1_ instanceof EntityLivingBase && !(p_70108_1_ instanceof EntityPlayer) && !(p_70108_1_ instanceof EntityIronGolem) && canBeRidden() && this.field_70159_w * this.field_70159_w + this.field_70179_y * this.field_70179_y > 0.01D && this.field_70153_n == null && p_70108_1_.field_70154_o == null)
                     {
                         p_70108_1_.func_70078_a(this);
                     }
@@ -876,7 +908,7 @@
                             double d7 = p_70108_1_.field_70159_w + this.field_70159_w;
                             double d8 = p_70108_1_.field_70179_y + this.field_70179_y;
 
-                            if (((EntityMinecart)p_70108_1_).func_180456_s() == EntityMinecart.EnumMinecartType.FURNACE && this.func_180456_s() != EntityMinecart.EnumMinecartType.FURNACE)
+                            if (((EntityMinecart)p_70108_1_).isPoweredCart() && !isPoweredCart())
                             {
                                 this.field_70159_w *= 0.20000000298023224D;
                                 this.field_70179_y *= 0.20000000298023224D;
@@ -884,7 +916,7 @@
                                 p_70108_1_.field_70159_w *= 0.949999988079071D;
                                 p_70108_1_.field_70179_y *= 0.949999988079071D;
                             }
-                            else if (((EntityMinecart)p_70108_1_).func_180456_s() != EntityMinecart.EnumMinecartType.FURNACE && this.func_180456_s() == EntityMinecart.EnumMinecartType.FURNACE)
+                            else if (((EntityMinecart)p_70108_1_).isPoweredCart() && isPoweredCart())
                             {
                                 p_70108_1_.field_70159_w *= 0.20000000298023224D;
                                 p_70108_1_.field_70179_y *= 0.20000000298023224D;
@@ -1049,6 +1081,221 @@
         }
     }
 
+    /* =================================== FORGE START ===========================================*/
+    private BlockPos getCurrentRailPosition()
+    {
+        int x = MathHelper.func_76128_c(this.field_70165_t);
+        int y = MathHelper.func_76128_c(this.field_70163_u);
+        int z = MathHelper.func_76128_c(this.field_70161_v);
+
+        if (BlockRailBase.func_176562_d(this.field_70170_p, new BlockPos(x, y - 1, z))) y--;
+        return new BlockPos(x, y, z);
+    }
+
+    protected double getMaxSpeed()
+    {
+        if (!canUseRail()) return func_174898_m();
+        BlockPos pos = this.getCurrentRailPosition();
+        IBlockState state = this.field_70170_p.func_180495_p(pos);
+        if (!BlockRailBase.func_176563_d(state)) return func_174898_m();
+
+        float railMaxSpeed = ((BlockRailBase)state.func_177230_c()).getRailMaxSpeed(field_70170_p, this, pos);
+        return Math.min(railMaxSpeed, getCurrentCartSpeedCapOnRail());
+    }
+
+    /**
+     * Moved to allow overrides.
+     * This code handles minecart movement and speed capping when on a rail.
+     */
+    public void moveMinecartOnRail(BlockPos pos)
+    {
+        double mX = this.field_70159_w;
+        double mZ = this.field_70179_y;
+
+        if (this.field_70153_n != null)
+        {
+            mX *= 0.75D;
+            mZ *= 0.75D;
+        }
+
+        double max = this.getMaxSpeed();
+        mX = MathHelper.func_151237_a(mX, -max, max);
+        mZ = MathHelper.func_151237_a(mZ, -max, max);
+        this.func_70091_d(mX, 0.0D, mZ);
+    }
+
+    /**
+     * Gets the current global Minecart Collision handler if none
+     * is registered, returns null
+     * @return The collision handler or null
+     */
+    public static net.minecraftforge.common.IMinecartCollisionHandler getCollisionHandler()
+    {
+        return collisionHandler;
+    }
+
+    /**
+     * Sets the global Minecart Collision handler, overwrites any
+     * that is currently set.
+     * @param handler The new handler
+     */
+    public static void setCollisionHandler(net.minecraftforge.common.IMinecartCollisionHandler handler)
+    {
+        collisionHandler = handler;
+    }
+
+    /**
+     * This function returns an ItemStack that represents this cart.
+     * This should be an ItemStack that can be used by the player to place the cart,
+     * but is not necessary the item the cart drops when destroyed.
+     * @return An ItemStack that can be used to place the cart.
+     */
+    public ItemStack getCartItem()
+    {
+        if (this instanceof EntityMinecartFurnace)
+        {
+            return new ItemStack(Items.field_151109_aJ);
+        }
+        else if (this instanceof EntityMinecartChest)
+        {
+            return new ItemStack(Items.field_151108_aI);
+        }
+        else if (this instanceof EntityMinecartTNT)
+        {
+            return new ItemStack(Items.field_151142_bV);
+        }
+        else if (this instanceof EntityMinecartHopper)
+        {
+            return new ItemStack(Items.field_151140_bW);
+        }
+        else if (this instanceof EntityMinecartHopper)
+        {
+            return new ItemStack(Items.field_151095_cc);
+        }
+        return new ItemStack(Items.field_151143_au);
+    }
+
+    /**
+     * Returns true if this cart can currently use rails.
+     * This function is mainly used to gracefully detach a minecart from a rail.
+     * @return True if the minecart can use rails.
+     */
+    public boolean canUseRail()
+    {
+        return canUseRail;
+    }
+
+    /**
+     * Set whether the minecart can use rails.
+     * This function is mainly used to gracefully detach a minecart from a rail.
+     * @param use Whether the minecart can currently use rails.
+     */
+    public void setCanUseRail(boolean use)
+    {
+        canUseRail = use;
+    }
+
+    /**
+     * Return false if this cart should not call onMinecartPass() and should ignore Powered Rails.
+     * @return True if this cart should call onMinecartPass().
+     */
+    public boolean shouldDoRailFunctions()
+    {
+        return true;
+    }
+
+    /**
+     * Returns true if this cart is self propelled.
+     * @return True if powered.
+     */
+    public boolean isPoweredCart()
+    {
+        return func_180456_s() == EntityMinecart.EnumMinecartType.FURNACE;
+    }
+
+    /**
+     * Returns true if this cart can be ridden by an Entity.
+     * @return True if this cart can be ridden.
+     */
+    public boolean canBeRidden()
+    {
+        return this.func_180456_s() == EntityMinecart.EnumMinecartType.RIDEABLE;
+    }
+
+    /**
+     * Getters/setters for physics variables
+     */
+
+    /**
+     * Returns the carts max speed when traveling on rails. Carts going faster
+     * than 1.1 cause issues with chunk loading. Carts cant traverse slopes or
+     * corners at greater than 0.5 - 0.6. This value is compared with the rails
+     * max speed and the carts current speed cap to determine the carts current
+     * max speed. A normal rail's max speed is 0.4.
+     *
+     * @return Carts max speed.
+     */
+    public float getMaxCartSpeedOnRail()
+    {
+        return 1.2f;
+    }
+
+    /**
+     * Returns the current speed cap for the cart when traveling on rails. This
+     * functions differs from getMaxCartSpeedOnRail() in that it controls
+     * current movement and cannot be overridden. The value however can never be
+     * higher than getMaxCartSpeedOnRail().
+     *
+     * @return
+     */
+    public final float getCurrentCartSpeedCapOnRail()
+    {
+        return currentSpeedRail;
+    }
+
+    public final void setCurrentCartSpeedCapOnRail(float value)
+    {
+        value = Math.min(value, getMaxCartSpeedOnRail());
+        currentSpeedRail = value;
+    }
+
+    public float getMaxSpeedAirLateral()
+    {
+        return maxSpeedAirLateral;
+    }
+
+    public void setMaxSpeedAirLateral(float value)
+    {
+        maxSpeedAirLateral = value;
+    }
+
+    public float getMaxSpeedAirVertical()
+    {
+        return maxSpeedAirVertical;
+    }
+
+    public void setMaxSpeedAirVertical(float value)
+    {
+        maxSpeedAirVertical = value;
+    }
+
+    public double getDragAir()
+    {
+        return dragAir;
+    }
+
+    public void setDragAir(double value)
+    {
+        dragAir = value;
+    }
+
+    public double getSlopeAdjustment()
+    {
+        return 0.0078125D;
+    }
+
+    /* =================================== FORGE END ===========================================*/
+
     public static enum EnumMinecartType
     {
         RIDEABLE(0, "MinecartRideable"),
