/*
 * This file is part of Sponge, licensed under the MIT License (MIT).
 *
 * Copyright (c) SpongePowered <https://www.spongepowered.org>
 * Copyright (c) contributors
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
package org.spongepowered.common.mixin.realtime.mixin;

import net.minecraft.entity.Entity;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.world.World;
import org.spongepowered.asm.lib.Opcodes;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Redirect;
import org.spongepowered.common.mixin.realtime.IMixinRealTimeTicking;

@Mixin(EntityPlayerMP.class)
public abstract class MixinEntityPlayerMP extends Entity {

    private static final String ENTITY_PLAYER_MP_PORTAL_COOLDOWN_FIELD = "Lnet/minecraft/entity/player/EntityPlayerMP;timeUntilPortal:I";

    public MixinEntityPlayerMP(World worldIn) {
        super(worldIn);
    }

    @Redirect(method = "decrementTimeUntilPortal", at = @At(value = "FIELD", target = ENTITY_PLAYER_MP_PORTAL_COOLDOWN_FIELD, opcode = Opcodes.PUTFIELD, ordinal = 0))
    public void fixupPortalCooldown(EntityPlayerMP self, int modifier) {
        int ticks = (int) ((IMixinRealTimeTicking) self.getEntityWorld()).getRealTimeTicks();
        this.timeUntilPortal = Math.max(0, this.timeUntilPortal - ticks);
    }

}

@@ -2318,16 +2318,739 @@
 icks();%0A
+        // The initially apparent function of timeUntilPortal is a cooldown for%0A        // nether portals. However, there is a much more important use:%0A        // preventing players from being immediately sent back to the other end%0A        // of the portal. Since it only checks timeUntilPortal to determine%0A        // whether the player was just in a portal, if timeUntilPortal gets set%0A        // to 0, it assumes the player left and reentered the portal (see%0A        // Entity.setPortal()). To prevent this, %22snag%22 the value of%0A        // timeUntilPortal at 1. If setPortal() does not reset it (the player%0A        // exits the portal), modifier will become 0, indicating that it is%0A        // OK to teleport the player.%0A
         
@@ -3081,16 +3081,35 @@
 ath.max(
+modifier %3E 0 ? 1 : 
 0, this.

Fix players being sent back through a nether portal they just used.