--- a/net/minecraft/world/chunk/Chunk.java
+++ b/net/minecraft/world/chunk/Chunk.java
@@ -58,7 +58,7 @@
 import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.Logger;
 
-public class Chunk implements IChunk {
+public class Chunk extends net.minecraftforge.common.capabilities.CapabilityProvider<Chunk> implements IChunk, net.minecraftforge.common.extensions.IForgeChunk {
    private static final Logger field_150817_t = LogManager.getLogger();
    @Nullable
    public static final ChunkSection field_186036_a = null;
@@ -92,6 +92,7 @@
    }
 
    public Chunk(World p_i225781_1_, ChunkPos p_i225781_2_, BiomeContainer p_i225781_3_, UpgradeData p_i225781_4_, ITickList<Block> p_i225781_5_, ITickList<Fluid> p_i225781_6_, long p_i225781_7_, @Nullable ChunkSection[] p_i225781_9_, @Nullable Consumer<Chunk> p_i225781_10_) {
+      super(Chunk.class);
       this.field_76645_j = new ClassInheritanceMultiMap[16];
       this.field_76637_e = p_i225781_1_;
       this.field_212816_F = p_i225781_2_;
@@ -119,7 +120,7 @@
             field_150817_t.warn("Could not set level chunk sections, array length is {} instead of {}", p_i225781_9_.length, this.field_76652_q.length);
          }
       }
-
+      this.gatherCapabilities();
    }
 
    public Chunk(World p_i49947_1_, ChunkPrimer p_i49947_2_) {
@@ -264,14 +265,14 @@
 
          if (!this.field_76637_e.field_72995_K) {
             blockstate.func_196947_b(this.field_76637_e, p_177436_1_, p_177436_2_, p_177436_3_);
-         } else if (block1 != block && block1 instanceof ITileEntityProvider) {
+         } else if ((block1 != block || !p_177436_2_.hasTileEntity()) && blockstate.hasTileEntity()) {
             this.field_76637_e.func_175713_t(p_177436_1_);
          }
 
          if (!chunksection.func_177485_a(i, j & 15, k).func_203425_a(block)) {
             return null;
          } else {
-            if (block1 instanceof ITileEntityProvider) {
+            if (blockstate.hasTileEntity()) {
                TileEntity tileentity = this.func_177424_a(p_177436_1_, Chunk.CreateEntityType.CHECK);
                if (tileentity != null) {
                   tileentity.func_145836_u();
@@ -282,10 +283,10 @@
                p_177436_2_.func_215705_a(this.field_76637_e, p_177436_1_, blockstate, p_177436_3_);
             }
 
-            if (block instanceof ITileEntityProvider) {
+            if (p_177436_2_.hasTileEntity()) {
                TileEntity tileentity1 = this.func_177424_a(p_177436_1_, Chunk.CreateEntityType.CHECK);
                if (tileentity1 == null) {
-                  tileentity1 = ((ITileEntityProvider)block).func_196283_a_(this.field_76637_e);
+                  tileentity1 = p_177436_2_.createTileEntity(this.field_76637_e);
                   this.field_76637_e.func_175690_a(p_177436_1_, tileentity1);
                } else {
                   tileentity1.func_145836_u();
@@ -321,11 +322,13 @@
          k = this.field_76645_j.length - 1;
       }
 
+      net.minecraftforge.common.MinecraftForge.EVENT_BUS.post(new net.minecraftforge.event.entity.EntityEvent.EnteringChunk(p_76612_1_, this.field_212816_F.field_77276_a, this.field_212816_F.field_77275_b, p_76612_1_.field_70176_ah, p_76612_1_.field_70164_aj));
       p_76612_1_.field_70175_ag = true;
       p_76612_1_.field_70176_ah = this.field_212816_F.field_77276_a;
       p_76612_1_.field_70162_ai = k;
       p_76612_1_.field_70164_aj = this.field_212816_F.field_77275_b;
       this.field_76645_j[k].add(p_76612_1_);
+      this.func_76630_e(); // Forge - ensure chunks are marked to save after an entity add
    }
 
    public void func_201607_a(Heightmap.Type p_201607_1_, long[] p_201607_2_) {
@@ -346,6 +349,7 @@
       }
 
       this.field_76645_j[p_76608_2_].remove(p_76608_1_);
+      this.func_76630_e(); // Forge - ensure chunks are marked to save after entity removals
    }
 
    public int func_201576_a(Heightmap.Type p_201576_1_, int p_201576_2_, int p_201576_3_) {
@@ -356,7 +360,7 @@
    private TileEntity func_177422_i(BlockPos p_177422_1_) {
       BlockState blockstate = this.func_180495_p(p_177422_1_);
       Block block = blockstate.func_177230_c();
-      return !block.func_235695_q_() ? null : ((ITileEntityProvider)block).func_196283_a_(this.field_76637_e);
+      return !blockstate.hasTileEntity() ? null : blockstate.createTileEntity(this.field_76637_e);
    }
 
    @Nullable
@@ -367,6 +371,10 @@
    @Nullable
    public TileEntity func_177424_a(BlockPos p_177424_1_, Chunk.CreateEntityType p_177424_2_) {
       TileEntity tileentity = this.field_150816_i.get(p_177424_1_);
+      if (tileentity != null && tileentity.func_145837_r()) {
+         field_150816_i.remove(p_177424_1_);
+         tileentity = null;
+      }
       if (tileentity == null) {
          CompoundNBT compoundnbt = this.field_201618_i.remove(p_177424_1_);
          if (compoundnbt != null) {
@@ -382,9 +390,6 @@
             tileentity = this.func_177422_i(p_177424_1_);
             this.field_76637_e.func_175690_a(p_177424_1_, tileentity);
          }
-      } else if (tileentity.func_145837_r()) {
-         this.field_150816_i.remove(p_177424_1_);
-         return null;
       }
 
       return tileentity;
@@ -399,7 +404,7 @@
    }
 
    public void func_177426_a(BlockPos p_177426_1_, TileEntity p_177426_2_) {
-      if (this.func_180495_p(p_177426_1_).func_177230_c() instanceof ITileEntityProvider) {
+      if (this.func_180495_p(p_177426_1_).hasTileEntity()) {
          p_177426_2_.func_226984_a_(this.field_76637_e, p_177426_1_);
          p_177426_2_.func_145829_t();
          TileEntity tileentity = this.field_150816_i.put(p_177426_1_.func_185334_h(), p_177426_2_);
@@ -418,9 +423,14 @@
    public CompoundNBT func_223134_j(BlockPos p_223134_1_) {
       TileEntity tileentity = this.func_175625_s(p_223134_1_);
       if (tileentity != null && !tileentity.func_145837_r()) {
+         try {
          CompoundNBT compoundnbt1 = tileentity.func_189515_b(new CompoundNBT());
          compoundnbt1.func_74757_a("keepPacked", false);
          return compoundnbt1;
+         } catch (Exception e) {
+            LogManager.getLogger().error("A TileEntity type {} has thrown an exception trying to write state. It will not persist, Report this to the mod author", tileentity.getClass().getName(), e);
+            return null;
+         }
       } else {
          CompoundNBT compoundnbt = this.field_201618_i.get(p_223134_1_);
          if (compoundnbt != null) {
@@ -455,8 +465,8 @@
    }
 
    public void func_177414_a(@Nullable Entity p_177414_1_, AxisAlignedBB p_177414_2_, List<Entity> p_177414_3_, @Nullable Predicate<? super Entity> p_177414_4_) {
-      int i = MathHelper.func_76128_c((p_177414_2_.field_72338_b - 2.0D) / 16.0D);
-      int j = MathHelper.func_76128_c((p_177414_2_.field_72337_e + 2.0D) / 16.0D);
+      int i = MathHelper.func_76128_c((p_177414_2_.field_72338_b - this.field_76637_e.getMaxEntityRadius()) / 16.0D);
+      int j = MathHelper.func_76128_c((p_177414_2_.field_72337_e + this.field_76637_e.getMaxEntityRadius()) / 16.0D);
       i = MathHelper.func_76125_a(i, 0, this.field_76645_j.length - 1);
       j = MathHelper.func_76125_a(j, 0, this.field_76645_j.length - 1);
 
@@ -486,8 +496,8 @@
    }
 
    public <T extends Entity> void func_217313_a(@Nullable EntityType<?> p_217313_1_, AxisAlignedBB p_217313_2_, List<? super T> p_217313_3_, Predicate<? super T> p_217313_4_) {
-      int i = MathHelper.func_76128_c((p_217313_2_.field_72338_b - 2.0D) / 16.0D);
-      int j = MathHelper.func_76128_c((p_217313_2_.field_72337_e + 2.0D) / 16.0D);
+      int i = MathHelper.func_76128_c((p_217313_2_.field_72338_b - this.field_76637_e.getMaxEntityRadius()) / 16.0D);
+      int j = MathHelper.func_76128_c((p_217313_2_.field_72337_e + this.field_76637_e.getMaxEntityRadius()) / 16.0D);
       i = MathHelper.func_76125_a(i, 0, this.field_76645_j.length - 1);
       j = MathHelper.func_76125_a(j, 0, this.field_76645_j.length - 1);
 
@@ -502,8 +512,8 @@
    }
 
    public <T extends Entity> void func_177430_a(Class<? extends T> p_177430_1_, AxisAlignedBB p_177430_2_, List<T> p_177430_3_, @Nullable Predicate<? super T> p_177430_4_) {
-      int i = MathHelper.func_76128_c((p_177430_2_.field_72338_b - 2.0D) / 16.0D);
-      int j = MathHelper.func_76128_c((p_177430_2_.field_72337_e + 2.0D) / 16.0D);
+      int i = MathHelper.func_76128_c((p_177430_2_.field_72338_b - this.field_76637_e.getMaxEntityRadius()) / 16.0D);
+      int j = MathHelper.func_76128_c((p_177430_2_.field_72337_e + this.field_76637_e.getMaxEntityRadius()) / 16.0D);
       i = MathHelper.func_76125_a(i, 0, this.field_76645_j.length - 1);
       j = MathHelper.func_76125_a(j, 0, this.field_76645_j.length - 1);
 
@@ -535,6 +545,11 @@
       };
       Sets.newHashSet(this.field_150816_i.keySet()).stream().filter(predicate).forEach(this.field_76637_e::func_175713_t);
 
+      for (TileEntity tileEntity : field_150816_i.values()) {
+         tileEntity.func_145836_u();
+         tileEntity.func_195044_w();
+      }
+
       for(int i = 0; i < this.field_76652_q.length; ++i) {
          ChunkSection chunksection = this.field_76652_q[i];
          if ((p_227073_4_ & 1 << i) == 0) {
@@ -598,7 +613,7 @@
 
    public Stream<BlockPos> func_217304_m() {
       return StreamSupport.stream(BlockPos.func_191531_b(this.field_212816_F.func_180334_c(), 0, this.field_212816_F.func_180333_d(), this.field_212816_F.func_180332_e(), 255, this.field_212816_F.func_180330_f()).spliterator(), false).filter((p_217312_1_) -> {
-         return this.func_180495_p(p_217312_1_).func_185906_d() != 0;
+         return this.func_180495_p(p_217312_1_).getLightValue(func_177412_p(), p_217312_1_) != 0;
       });
    }
 
@@ -704,9 +719,8 @@
       BlockState blockstate = this.func_180495_p(p_212815_1_);
       TileEntity tileentity;
       if ("DUMMY".equals(p_212815_2_.func_74779_i("id"))) {
-         Block block = blockstate.func_177230_c();
-         if (block instanceof ITileEntityProvider) {
-            tileentity = ((ITileEntityProvider)block).func_196283_a_(this.field_76637_e);
+         if (blockstate.hasTileEntity()) {
+            tileentity = blockstate.createTileEntity(this.field_76637_e);
          } else {
             tileentity = null;
             field_150817_t.warn("Tried to load a DUMMY block entity @ {} but found not block entity block {} at location", p_212815_1_, blockstate);
@@ -795,4 +809,30 @@
       QUEUED,
       CHECK;
    }
+
+   /**
+    * <strong>FOR INTERNAL USE ONLY</strong>
+    * <p>
+    * Only public for use in {@link AnvilChunkLoader}.
+    */
+   @java.lang.Deprecated
+   @javax.annotation.Nullable
+   public final CompoundNBT writeCapsToNBT() {
+      return this.serializeCaps();
+   }
+
+   /**
+    * <strong>FOR INTERNAL USE ONLY</strong>
+    * <p>
+    * Only public for use in {@link AnvilChunkLoader}.
+    */
+   @java.lang.Deprecated
+   public final void readCapsFromNBT(CompoundNBT tag) {
+      this.deserializeCaps(tag);
+   }
+
+   @Override
+   public World getWorldForge() {
+      return func_177412_p();
+   }
 }
