/*
 * 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.server.mixin.exploit;

import net.minecraft.entity.Entity;
import net.minecraft.world.World;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Redirect;
import org.spongepowered.common.bridge.entity.EntityBridge;
import org.spongepowered.common.bridge.world.WorldBridge;

/**
 * A variety of exploit patches that are pulled from Paper that directly
 * intermixes a few fixes (patches) as one bundle due to their interconnected
 * nature.
 */
@Mixin(Entity.class)
public abstract class EntityMixin_ChunkLoadOnPositionSet implements EntityBridge {

    @Shadow public World world;

    @Shadow public abstract void setPosition(double x, double y, double z);

    /**
     * @author Aikar - August 16th, 2018
     * @reason Player Movement, Entity Creation, and Teleportation move
     * entities with a very "You are here, no debate" change, making
     * the server register them as there, regardless if the chunk was
     * loaded or not.
     *
     * It appears possible that with hack clients and lag, a player
     * may be able to move fast enough to move into an unloaded chunk
     * and get into a buggy state.
     *
     * To prevent this, we will ensure a chunk is always loaded,
     * guaranteeing that the entity will be properly registered
     * into its new home comfortably.
     *
     * Permission by Aikar to have ported this patch along with other
     * patches for the Sponge project.
     * @see <html>https://github.com/PaperMC/Paper/blob/fd1bd5223a461b6d98280bb8f2d67280a30dd24a/Spigot-Server-Patches/0335-Ensure-chunks-are-always-loaded-on-hard-position-set.patch</html>
     *
     * @param entity This entity (this)
     * @param x The x location (this.posX)
     * @param y The y location (this.posY)
     * @param z The z location (this.posZ)
     */
    @Redirect(
        method = "setPositionAndRotation",
        at = @At(
            value = "INVOKE",
            target = "Lnet/minecraft/entity/Entity;setPosition(DDD)V"
        )
    )
    private void chunkLoadPositionReset$onSetPositionMarkWorldChunkAsLoaded(final Entity entity, final double x, final double y, final double z) {
        // Sponge - Make sure the chunk is marked as loaded
        if (!((WorldBridge) this.world).bridge$isFake()) {
            this.world.getChunk((int) Math.floor(x) >> 4, (int) Math.floor(z) >> 4);
        }
        // then continue to set the position
        this.setPosition(x, y, z);
    }

}
