--- a/net/minecraft/entity/player/ServerPlayerEntity.java
+++ b/net/minecraft/entity/player/ServerPlayerEntity.java
@@ -475,6 +475,7 @@
    }
 
    public void func_70645_a(DamageSource p_70645_1_) {
+      if (net.minecraftforge.common.ForgeHooks.onLivingDeath(this, p_70645_1_)) return;
       boolean flag = this.field_70170_p.func_82736_K().func_223586_b(GameRules.field_223609_l);
       if (flag) {
          ITextComponent itextcomponent = this.func_110142_aN().func_151521_b();
@@ -618,13 +619,14 @@
    }
 
    @Nullable
-   public Entity func_241206_a_(ServerWorld p_241206_1_) {
+   public Entity changeDimension(ServerWorld p_241206_1_, net.minecraftforge.common.util.ITeleporter teleporter) {
+      if (!net.minecraftforge.common.ForgeHooks.onTravelToDimension(this, p_241206_1_.func_234923_W_())) return null;
       this.field_184851_cj = true;
       ServerWorld serverworld = this.func_71121_q();
       RegistryKey<World> registrykey = serverworld.func_234923_W_();
-      if (registrykey == World.field_234920_i_ && p_241206_1_.func_234923_W_() == World.field_234918_g_) {
+      if (registrykey == World.field_234920_i_ && p_241206_1_.func_234923_W_() == World.field_234918_g_ && teleporter.isVanilla()) { //Forge: Fix non-vanilla teleporters triggering end credits
          this.func_213319_R();
-         this.func_71121_q().func_217434_e(this);
+         this.func_71121_q().removePlayer(this, true); //Forge: The player entity is cloned so keep the data until after cloning calls copyFrom
          if (!this.field_71136_j) {
             this.field_71136_j = true;
             this.field_71135_a.func_147359_a(new SChangeGameStatePacket(SChangeGameStatePacket.field_241768_e_, this.field_192040_cp ? 0.0F : 1.0F));
@@ -638,14 +640,15 @@
          this.field_71135_a.func_147359_a(new SServerDifficultyPacket(iworldinfo.func_176130_y(), iworldinfo.func_176123_z()));
          PlayerList playerlist = this.field_71133_b.func_184103_al();
          playerlist.func_187243_f(this);
-         serverworld.func_217434_e(this);
-         this.field_70128_L = false;
-         PortalInfo portalinfo = this.func_241829_a(p_241206_1_);
+         serverworld.removeEntity(this, true); //Forge: the player entity is moved to the new world, NOT cloned. So keep the data alive with no matching invalidate call.
+         this.revive();
+         PortalInfo portalinfo = teleporter.getPortalInfo(this, p_241206_1_, this::func_241829_a);
          if (portalinfo != null) {
+            Entity e = teleporter.placeEntity(this, serverworld, p_241206_1_, this.field_70177_z, spawnPortal -> {//Forge: Start vanilla logic
             serverworld.func_217381_Z().func_76320_a("moving");
             if (registrykey == World.field_234918_g_ && p_241206_1_.func_234923_W_() == World.field_234919_h_) {
                this.field_193110_cw = this.func_213303_ch();
-            } else if (p_241206_1_.func_234923_W_() == World.field_234920_i_) {
+            } else if (spawnPortal && p_241206_1_.func_234923_W_() == World.field_234920_i_) {
                this.func_242110_a(p_241206_1_, new BlockPos(portalinfo.field_222505_a));
             }
 
@@ -657,6 +660,9 @@
             this.func_225653_b_(portalinfo.field_222505_a.field_72450_a, portalinfo.field_222505_a.field_72448_b, portalinfo.field_222505_a.field_72449_c);
             serverworld.func_217381_Z().func_76319_b();
             this.func_213846_b(serverworld);
+            return this;//forge: this is part of the ITeleporter patch
+            });//Forge: End vanilla logic
+            if (e != this) throw new java.lang.IllegalArgumentException(String.format("Teleporter %s returned not the player entity but instead %s, expected PlayerEntity %s", teleporter, e, this));
             this.field_71134_c.func_73080_a(p_241206_1_);
             this.field_71135_a.func_147359_a(new SPlayerAbilitiesPacket(this.field_71075_bZ));
             playerlist.func_72354_b(this, p_241206_1_);
@@ -670,6 +676,7 @@
             this.field_71144_ck = -1;
             this.field_71149_ch = -1.0F;
             this.field_71146_ci = -1;
+            net.minecraftforge.fml.hooks.BasicEventHooks.firePlayerChangedDimensionEvent(this, registrykey, p_241206_1_.func_234923_W_());
          }
 
          return this;
@@ -743,6 +750,9 @@
    }
 
    public Either<PlayerEntity.SleepResult, Unit> func_213819_a(BlockPos p_213819_1_) {
+      java.util.Optional<BlockPos> optAt = java.util.Optional.of(p_213819_1_);
+      PlayerEntity.SleepResult ret = net.minecraftforge.event.ForgeEventFactory.onPlayerSleepInBed(this, optAt);
+      if (ret != null) return Either.left(ret);
       Direction direction = this.field_70170_p.func_180495_p(p_213819_1_).func_177229_b(HorizontalBlock.field_185512_D);
       if (!this.func_70608_bn() && this.func_70089_S()) {
          if (!this.field_70170_p.func_230315_m_().func_236043_f_()) {
@@ -753,7 +763,7 @@
             return Either.left(PlayerEntity.SleepResult.OBSTRUCTED);
          } else {
             this.func_242111_a(this.field_70170_p.func_234923_W_(), p_213819_1_, this.field_70177_z, false, true);
-            if (this.field_70170_p.func_72935_r()) {
+            if (!net.minecraftforge.event.ForgeEventFactory.fireSleepingTimeCheck(this, optAt)) {
                return Either.left(PlayerEntity.SleepResult.NOT_POSSIBLE_NOW);
             } else {
                if (!this.func_184812_l_()) {
@@ -787,6 +797,7 @@
    }
 
    private boolean func_241147_a_(BlockPos p_241147_1_, Direction p_241147_2_) {
+      if (p_241147_2_ == null) return false;
       return this.func_241158_g_(p_241147_1_) || this.func_241158_g_(p_241147_1_.func_177972_a(p_241147_2_.func_176734_d()));
    }
 
@@ -886,6 +897,7 @@
             this.field_71135_a.func_147359_a(new SOpenWindowPacket(container.field_75152_c, container.func_216957_a(), p_213829_1_.func_145748_c_()));
             container.func_75132_a(this);
             this.field_71070_bA = container;
+            net.minecraftforge.common.MinecraftForge.EVENT_BUS.post(new net.minecraftforge.event.entity.player.PlayerContainerEvent.Open(this, this.field_71070_bA));
             return OptionalInt.of(this.field_71139_cq);
          }
       }
@@ -904,6 +916,7 @@
       this.field_71135_a.func_147359_a(new SOpenHorseWindowPacket(this.field_71139_cq, p_184826_2_.func_70302_i_(), p_184826_1_.func_145782_y()));
       this.field_71070_bA = new HorseInventoryContainer(this.field_71139_cq, this.field_71071_by, p_184826_2_, p_184826_1_);
       this.field_71070_bA.func_75132_a(this);
+      net.minecraftforge.common.MinecraftForge.EVENT_BUS.post(new net.minecraftforge.event.entity.player.PlayerContainerEvent.Open(this, this.field_71070_bA));
    }
 
    public void func_184814_a(ItemStack p_184814_1_, Hand p_184814_2_) {
@@ -961,6 +974,7 @@
 
    public void func_71128_l() {
       this.field_71070_bA.func_75134_a(this);
+      net.minecraftforge.common.MinecraftForge.EVENT_BUS.post(new net.minecraftforge.event.entity.player.PlayerContainerEvent.Close(this, this.field_71070_bA));
       this.field_71070_bA = this.field_71069_bz;
    }
 
@@ -1085,6 +1099,13 @@
       this.field_193110_cw = p_193104_1_.field_193110_cw;
       this.func_192029_h(p_193104_1_.func_192023_dk());
       this.func_192031_i(p_193104_1_.func_192025_dl());
+
+      //Copy over a section of the Entity Data from the old player.
+      //Allows mods to specify data that persists after players respawn.
+      CompoundNBT old = p_193104_1_.getPersistentData();
+      if (old.func_74764_b(PERSISTED_NBT_TAG))
+          getPersistentData().func_218657_a(PERSISTED_NBT_TAG, old.func_74781_a(PERSISTED_NBT_TAG));
+      net.minecraftforge.event.ForgeEventFactory.onPlayerClone(this, p_193104_1_, !p_193104_2_);
    }
 
    protected void func_70670_a(EffectInstance p_70670_1_) {
@@ -1143,6 +1164,7 @@
    }
 
    public void func_71033_a(GameType p_71033_1_) {
+      if (!net.minecraftforge.common.ForgeHooks.onChangeGameMode(this, this.field_71134_c.func_73081_b(), p_71033_1_)) return;
       this.field_71134_c.func_73076_a(p_71033_1_);
       this.field_71135_a.func_147359_a(new SChangeGameStatePacket(SChangeGameStatePacket.field_241767_d_, (float)p_71033_1_.func_77148_a()));
       if (p_71033_1_ == GameType.SPECTATOR) {
@@ -1191,6 +1213,7 @@
       this.field_71140_co = p_147100_1_.func_149520_f();
       this.func_184212_Q().func_187227_b(field_184827_bp, (byte)p_147100_1_.func_149521_d());
       this.func_184212_Q().func_187227_b(field_184828_bq, (byte)(p_147100_1_.func_186991_f() == HandSide.LEFT ? 0 : 1));
+      this.language = p_147100_1_.getLanguage();
    }
 
    public ChatVisibility func_147096_v() {
@@ -1301,14 +1324,14 @@
       this.func_184210_p();
       if (p_200619_1_ == this.field_70170_p) {
          this.field_71135_a.func_147364_a(p_200619_2_, p_200619_4_, p_200619_6_, p_200619_8_, p_200619_9_);
-      } else {
+      } else if (net.minecraftforge.common.ForgeHooks.onTravelToDimension(this, p_200619_1_.func_234923_W_())) {
          ServerWorld serverworld = this.func_71121_q();
          IWorldInfo iworldinfo = p_200619_1_.func_72912_H();
          this.field_71135_a.func_147359_a(new SRespawnPacket(p_200619_1_.func_230315_m_(), p_200619_1_.func_234923_W_(), BiomeManager.func_235200_a_(p_200619_1_.func_72905_C()), this.field_71134_c.func_73081_b(), this.field_71134_c.func_241815_c_(), p_200619_1_.func_234925_Z_(), p_200619_1_.func_241109_A_(), true));
          this.field_71135_a.func_147359_a(new SServerDifficultyPacket(iworldinfo.func_176130_y(), iworldinfo.func_176123_z()));
          this.field_71133_b.func_184103_al().func_187243_f(this);
-         serverworld.func_217434_e(this);
-         this.field_70128_L = false;
+         serverworld.removePlayer(this, true); //Forge: The player entity itself is moved, and not cloned. So we need to keep the data alive with no matching invalidate call later.
+         this.revive();
          this.func_70012_b(p_200619_2_, p_200619_4_, p_200619_6_, p_200619_8_, p_200619_9_);
          this.func_70029_a(p_200619_1_);
          p_200619_1_.func_217446_a(this);
@@ -1317,6 +1340,7 @@
          this.field_71134_c.func_73080_a(p_200619_1_);
          this.field_71133_b.func_184103_al().func_72354_b(this, p_200619_1_);
          this.field_71133_b.func_184103_al().func_72385_f(this);
+         net.minecraftforge.fml.hooks.BasicEventHooks.firePlayerChangedDimensionEvent(this, serverworld.func_234923_W_(), p_200619_1_.func_234923_W_());
       }
 
    }
@@ -1339,6 +1363,7 @@
    }
 
    public void func_242111_a(RegistryKey<World> p_242111_1_, @Nullable BlockPos p_242111_2_, float p_242111_3_, boolean p_242111_4_, boolean p_242111_5_) {
+      if (net.minecraftforge.event.ForgeEventFactory.onPlayerSpawnSet(this, p_242111_2_ == null ? World.field_234918_g_ : p_242111_1_, p_242111_2_, p_242111_4_)) return;
       if (p_242111_2_ != null) {
          boolean flag = p_242111_2_.equals(this.field_241138_cr_) && p_242111_1_.equals(this.field_241137_cq_);
          if (p_242111_5_ && !flag) {
@@ -1391,6 +1416,8 @@
       if (itementity == null) {
          return null;
       } else {
+         if (captureDrops() != null) captureDrops().add(itementity);
+         else
          this.field_70170_p.func_217376_c(itementity);
          ItemStack itemstack = itementity.func_92059_d();
          if (p_146097_3_) {
@@ -1405,6 +1432,15 @@
       }
    }
 
+   private String language = "en_us";
+   /**
+    * Returns the language last reported by the player as their local language.
+    * Defaults to en_us if the value is unknown.
+    */
+   public String getLanguage() {
+      return this.language;
+   }
+
    @Nullable
    public IChatFilter func_244529_Q() {
       return this.field_244528_co;
