From 7a5d7aecb6926cbf95f0d3361a5369d98c338366 Mon Sep 17 00:00:00 2001
From: Runemoro <runemoro@users.noreply.github.com>
Date: Mon, 23 Apr 2018 00:45:00 -0400
Subject: [PATCH] Fix players being set on fire after teleporting

---
 build.gradle                                  |  36 +++-
 .../vanillafix/VanillaFixCoreContainer.java   |  24 +++
 .../dimdev/vanillafix/VanillaFixCoreMod.java  |  38 ++++
 .../mixins/MixinNetHandlerPlayServer.java     | 173 ++++++++++++++++++
 .../org.dimdev.vanillafix.mixins.json         |  18 ++
 5 files changed, 287 insertions(+), 2 deletions(-)
 create mode 100644 src/main/java/org/dimdev/vanillafix/VanillaFixCoreContainer.java
 create mode 100644 src/main/java/org/dimdev/vanillafix/VanillaFixCoreMod.java
 create mode 100644 src/main/java/org/dimdev/vanillafix/mixins/MixinNetHandlerPlayServer.java
 create mode 100644 src/main/resources/org.dimdev.vanillafix.mixins.json

diff --git a/build.gradle b/build.gradle
index 82dafc3d..32637436 100644
--- a/build.gradle
+++ b/build.gradle
@@ -2,9 +2,11 @@ buildscript {
     repositories {
         jcenter()
         maven { url = "http://files.minecraftforge.net/maven" }
+        maven { url = "http://repo.spongepowered.org/maven" }
     }
     dependencies {
         classpath 'net.minecraftforge.gradle:ForgeGradle:2.3-SNAPSHOT'
+        classpath 'org.spongepowered:mixingradle:0.6-SNAPSHOT'
     }
 }
 
@@ -15,13 +17,20 @@ plugins {
 
 apply plugin: 'java'
 apply plugin: 'net.minecraftforge.gradle.forge'
+apply plugin: 'org.spongepowered.mixin'
 
 repositories {
-    maven { url "https://jitpack.io" }
+    maven { url = "https://jitpack.io" }
+    maven {
+        name = 'sonatype'
+        url = 'http://oss.sonatype.org/content/repositories/public/'
+    }
+    maven { url = "http://repo.spongepowered.org/maven" }
 }
 
 configurations {
     embed
+    coreShadow
     compile.extendsFrom(embed)
 }
 
@@ -30,7 +39,8 @@ dependencies {
     embed 'org.jgrapht:jgrapht-core:1.1.0'
     embed 'com.github.DimensionalDevelopment:poly2tri.java:master-SNAPSHOT'
     compileOnly 'com.github.DimensionalDevelopment:AnnotatedNBT:-SNAPSHOT'
-    compileOnly 'com.github.OpenCubicChunks:CubicChunks:MC_1.12-SNAPSHOT'
+    compile("org.spongepowered:mixin:0.7.8-SNAPSHOT") { transitive = false }
+    deobfProvided 'io.github.opencubicchunks:cubicchunks:1.12.2-0.0.819.0-SNAPSHOT'
 }
 
 // Mod version
@@ -63,6 +73,19 @@ minecraft {
     mappings = mcpversion
     replace '${version}', fullVersion
     makeObfSourceJar = false
+    //noinspection GroovyUnusedAssignment
+    def args = [ // TODO: https://github.com/SpongePowered/Mixin/issues/140
+            "-Dfml.noGrab=false",
+            "-Dfml.coreMods.load=org.dimdev.vanillafix.VanillaFixCoreMod",
+            "-Dmixin.env.compatLevel=JAVA_8",
+            //"-Dmixin.debug.verbose=true",
+            //"-Dmixin.debug.export=true",
+            "-Dmixin.checks.interfaces=true"
+    ]
+}
+
+mixin {
+    add sourceSets.main, "org.dimdev.vanillafix.mixins.refmap.json"
 }
 
 // Tasks
@@ -73,6 +96,15 @@ compileJava {
 jar {
     archiveName = archivesBaseName + "-" + jarVersion + ".jar"
     from configurations.embed.collect { it.isDirectory() ? it : zipTree(it) }
+    manifest {
+        attributes(
+                "TweakClass": "org.spongepowered.asm.launch.MixinTweaker",
+                "FMLCorePlugin": "org.dimdev.vanillafix.VanillaFixCoreMod",
+                "TweakOrder": 0,
+                "MixinConfigs": "org.dimdev.vanillafix.mixins.json",
+                "ForceLoadAsMod": "true"
+        )
+    }
 }
 
 task sourcesJar(type: Jar, dependsOn: classes) {
diff --git a/src/main/java/org/dimdev/vanillafix/VanillaFixCoreContainer.java b/src/main/java/org/dimdev/vanillafix/VanillaFixCoreContainer.java
new file mode 100644
index 00000000..1c4adebb
--- /dev/null
+++ b/src/main/java/org/dimdev/vanillafix/VanillaFixCoreContainer.java
@@ -0,0 +1,24 @@
+package org.dimdev.vanillafix;
+
+import net.minecraftforge.fml.common.DummyModContainer;
+import net.minecraftforge.fml.common.ModMetadata;
+import net.minecraftforge.fml.common.versioning.ArtifactVersion;
+
+import java.util.Collections;
+import java.util.List;
+
+public class VanillaFixCoreContainer extends DummyModContainer {
+
+    public VanillaFixCoreContainer() {
+        super(new ModMetadata());
+        ModMetadata meta = getMetadata();
+        meta.modId = "cubicchunkscore";
+        meta.name = "VanillaFix";
+        meta.version = "${version}";
+    }
+
+    @Override
+    public List<ArtifactVersion> getDependencies() {
+        return Collections.emptyList();
+    }
+}
\ No newline at end of file
diff --git a/src/main/java/org/dimdev/vanillafix/VanillaFixCoreMod.java b/src/main/java/org/dimdev/vanillafix/VanillaFixCoreMod.java
new file mode 100644
index 00000000..7157e2af
--- /dev/null
+++ b/src/main/java/org/dimdev/vanillafix/VanillaFixCoreMod.java
@@ -0,0 +1,38 @@
+package org.dimdev.vanillafix;
+
+import net.minecraftforge.common.ForgeVersion;
+import net.minecraftforge.fml.relauncher.IFMLLoadingPlugin;
+import org.spongepowered.asm.launch.MixinBootstrap;
+import org.spongepowered.asm.mixin.Mixins;
+
+import javax.annotation.Nullable;
+import java.util.Map;
+
+@IFMLLoadingPlugin.MCVersion(ForgeVersion.mcVersion)
+@IFMLLoadingPlugin.SortingIndex(5000)
+@IFMLLoadingPlugin.TransformerExclusions("org.dimdev.vanillafix.")
+public class VanillaFixCoreMod implements IFMLLoadingPlugin {
+
+    public VanillaFixCoreMod() {
+        MixinBootstrap.init();
+        Mixins.addConfiguration("org.dimdev.vanillafix.mixins.json");
+    }
+
+    @Override public String[] getASMTransformerClass() {
+        return new String[0];
+    }
+
+    @Override public String getModContainerClass() {
+        return "org.dimdev.vanillafix.VanillaFixCoreContainer";
+    }
+
+    @Nullable @Override public String getSetupClass() {
+        return null;
+    }
+
+    @Override public void injectData(Map<String, Object> data) {}
+
+    @Override public String getAccessTransformerClass() {
+        return null;
+    }
+}
diff --git a/src/main/java/org/dimdev/vanillafix/mixins/MixinNetHandlerPlayServer.java b/src/main/java/org/dimdev/vanillafix/mixins/MixinNetHandlerPlayServer.java
new file mode 100644
index 00000000..95cf1e24
--- /dev/null
+++ b/src/main/java/org/dimdev/vanillafix/mixins/MixinNetHandlerPlayServer.java
@@ -0,0 +1,173 @@
+package org.dimdev.vanillafix.mixins;
+
+import net.minecraft.entity.MoverType;
+import net.minecraft.entity.player.EntityPlayerMP;
+import net.minecraft.init.MobEffects;
+import net.minecraft.network.NetHandlerPlayServer;
+import net.minecraft.network.PacketThreadUtil;
+import net.minecraft.network.play.INetHandlerPlayServer;
+import net.minecraft.network.play.client.CPacketPlayer;
+import net.minecraft.server.MinecraftServer;
+import net.minecraft.util.math.Vec3d;
+import net.minecraft.util.text.ITextComponent;
+import net.minecraft.util.text.TextComponentTranslation;
+import net.minecraft.world.GameType;
+import net.minecraft.world.WorldServer;
+import org.apache.logging.log4j.Logger;
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.Overwrite;
+import org.spongepowered.asm.mixin.Shadow;
+
+@SuppressWarnings("unused") // Shadow
+@Mixin(NetHandlerPlayServer.class)
+public abstract class MixinNetHandlerPlayServer implements INetHandlerPlayServer {
+
+    @Shadow public EntityPlayerMP player;
+    @Shadow private /*final*/ MinecraftServer server;
+    @Shadow private int networkTickCount;
+    @Shadow private double firstGoodX;
+    @Shadow private double firstGoodY;
+    @Shadow private double firstGoodZ;
+    @Shadow private double lastGoodX;
+    @Shadow private double lastGoodY;
+    @Shadow private double lastGoodZ;
+    @Shadow private int lastPositionUpdate;
+    @Shadow private boolean floating;
+    @Shadow private Vec3d targetPos;
+    @Shadow private static final Logger LOGGER = null;
+    @Shadow private int movePacketCounter;
+    @Shadow private int lastMovePacketCounter;
+
+    @Shadow public void disconnect(final ITextComponent textComponent) {}
+
+    @Shadow private static boolean isMovePlayerPacketInvalid(CPacketPlayer packetIn) { return false; }
+
+    @Shadow private void captureCurrentPosition() {}
+
+    @Shadow public void setPlayerLocation(double x, double y, double z, float yaw, float pitch) {}
+
+    @Overwrite
+    @Override
+    public void processPlayer(CPacketPlayer packet) {
+        PacketThreadUtil.checkThreadAndEnqueue(packet, this, player.getServerWorld());
+
+        if (isMovePlayerPacketInvalid(packet)) {
+            disconnect(new TextComponentTranslation("multiplayer.disconnect.invalid_player_movement"));
+        } else {
+            WorldServer world = server.getWorld(player.dimension);
+
+            if (player.queuedEndExit) return;
+
+            if (networkTickCount == 0) {
+                captureCurrentPosition();
+            }
+
+            if (targetPos != null) {
+                if (networkTickCount - lastPositionUpdate > 20) {
+                    lastPositionUpdate = networkTickCount;
+                    setPlayerLocation(targetPos.x, targetPos.y, targetPos.z, player.rotationYaw, player.rotationPitch);
+                }
+            } else {
+                lastPositionUpdate = networkTickCount;
+
+                if (player.isRiding()) {
+                    player.setPositionAndRotation(player.posX, player.posY, player.posZ, packet.getYaw(player.rotationYaw), packet.getPitch(player.rotationPitch));
+                    server.getPlayerList().serverUpdateMovingPlayer(player);
+                } else {
+                    double oldX = player.posX;
+                    double oldY = player.posY;
+                    double oldZ = player.posZ;
+                    double oldY2 = player.posY;
+
+                    double packetX = packet.getX(player.posX);
+                    double packetY = packet.getY(player.posY);
+                    double packetZ = packet.getZ(player.posZ);
+                    float packetYaw = packet.getYaw(player.rotationYaw);
+                    float packetPitch = packet.getPitch(player.rotationPitch);
+
+                    double xDiff = packetX - firstGoodX;
+                    double yDiff = packetY - firstGoodY;
+                    double zDiff = packetZ - firstGoodZ;
+                    double speedSq = player.motionX * player.motionX + player.motionY * player.motionY + player.motionZ * player.motionZ;
+                    double distanceSq = xDiff * xDiff + yDiff * yDiff + zDiff * zDiff;
+
+                    if (player.isPlayerSleeping()) {
+                        if (distanceSq > 1.0D) {
+                            setPlayerLocation(player.posX, player.posY, player.posZ, packet.getYaw(player.rotationYaw), packet.getPitch(player.rotationPitch));
+                        }
+                    } else {
+                        ++movePacketCounter;
+                        int packetCount = movePacketCounter - lastMovePacketCounter;
+
+                        if (packetCount > 5) {
+                            LOGGER.debug("{} is sending move packets too frequently ({} packets since last tick)", player.getName(), packetCount);
+                            packetCount = 1;
+                        }
+
+                        if (!player.isInvulnerableDimensionChange() && (!player.getServerWorld().getGameRules().getBoolean("disableElytraMovementCheck") || !player.isElytraFlying())) {
+                            float maxDistancePerTic = player.isElytraFlying() ? 300.0F : 100.0F;
+
+                            if (distanceSq - speedSq > maxDistancePerTic * packetCount && (!server.isSinglePlayer() || !server.getServerOwner().equals(player.getName()))) {
+                                LOGGER.warn("{} moved too quickly! {},{},{}", player.getName(), xDiff, yDiff, zDiff);
+                                setPlayerLocation(player.posX, player.posY, player.posZ, player.rotationYaw, player.rotationPitch);
+                                return;
+                            }
+                        }
+
+                        boolean notInsideBlock = world.getCollisionBoxes(player, player.getEntityBoundingBox().shrink(0.0625D)).isEmpty();
+                        xDiff = packetX - lastGoodX;
+                        yDiff = packetY - lastGoodY;
+                        zDiff = packetZ - lastGoodZ;
+
+                        if (player.onGround && !packet.isOnGround() && yDiff > 0.0D) {
+                            player.jump();
+                        }
+
+                        player.move(MoverType.PLAYER, xDiff, yDiff, zDiff);
+                        player.onGround = packet.isOnGround();
+                        double oldYDiff = yDiff;
+
+                        xDiff = packetX - player.posX;
+                        yDiff = packetY - player.posY;
+                        if (yDiff > -0.5D || yDiff < 0.5D) { // TODO: But why?
+                            yDiff = 0.0D;
+                        }
+                        zDiff = packetZ - player.posZ;
+                        distanceSq = xDiff * xDiff + yDiff * yDiff + zDiff * zDiff;
+
+                        boolean movedWrongly = false;
+                        if (!player.isInvulnerableDimensionChange() && distanceSq > 0.0625D && !player.isPlayerSleeping() && !player.interactionManager.isCreative() && player.interactionManager.getGameType() != GameType.SPECTATOR) {
+                            movedWrongly = true;
+                            LOGGER.warn("{} moved wrongly!", player.getName());
+                        }
+
+                        // Fix https://bugs.mojang.com/browse/MC-98153
+                        //player.setPositionAndRotation(packetX, packetY, packetZ, packetYaw, packetPitch);
+                        //player.addMovementStat(player.posX - oldX, player.posY - oldY, player.posZ - oldZ);
+                        player.addMovementStat(packetX - oldX, packetY - oldY, packetZ - oldZ);
+
+                        // Fix https://bugs.mojang.com/browse/MC-123364 (partially, players can still cheat to teleport into a portal)
+                        if (!player.isInvulnerableDimensionChange() && !player.noClip && !player.isPlayerSleeping()) {
+                            boolean oldPositionEmpty = world.getCollisionBoxes(player, player.getEntityBoundingBox().shrink(0.0625D)).isEmpty();
+
+                            if (notInsideBlock && (movedWrongly || !oldPositionEmpty)) {
+                                setPlayerLocation(oldX, oldY, oldZ, packetYaw, packetPitch);
+                                return;
+                            }
+                        }
+
+                        floating = oldYDiff >= -0.03125D;
+                        floating &= !server.isFlightAllowed() && !player.capabilities.allowFlying;
+                        floating &= !player.isPotionActive(MobEffects.LEVITATION) && !player.isElytraFlying() && !world.checkBlockCollision(player.getEntityBoundingBox().grow(0.0625D).expand(0.0D, -0.55D, 0.0D));
+                        player.onGround = packet.isOnGround();
+                        server.getPlayerList().serverUpdateMovingPlayer(player);
+                        player.handleFalling(player.posY - oldY2, packet.isOnGround());
+                        lastGoodX = player.posX;
+                        lastGoodY = player.posY;
+                        lastGoodZ = player.posZ;
+                    }
+                }
+            }
+        }
+    }
+}
diff --git a/src/main/resources/org.dimdev.vanillafix.mixins.json b/src/main/resources/org.dimdev.vanillafix.mixins.json
new file mode 100644
index 00000000..341185f8
--- /dev/null
+++ b/src/main/resources/org.dimdev.vanillafix.mixins.json
@@ -0,0 +1,18 @@
+{
+  "required": true,
+  "package": "org.dimdev.vanillafix.mixins",
+  "refmap": "org.dimdev.vanillafix.mixins.refmap.json",
+  "compatibilityLevel": "JAVA_8",
+  "minVersion": "0.6.15-SNAPSHOT",
+  "mixins": [
+    "MixinNetHandlerPlayServer"
+  ],
+  "client": [],
+  "server": [],
+  "injectors": {
+    "defaultRequire": 1
+  },
+  "overwrites": {
+    "conformVisibility": true
+  }
+}