mirror of
https://github.com/NoCheatPlus/NoCheatPlus.git
synced 2025-02-07 23:32:01 +01:00
Minor optimizations.
This commit is contained in:
parent
836f3af19d
commit
f68cb5435d
@ -73,7 +73,6 @@ public class ChatData extends AsyncCheckData {
|
||||
public long noPwnageJoinTime;
|
||||
public String noPwnageLastMessage;
|
||||
public long noPwnageLastMessageTime;
|
||||
public long noPwnageLastMovedTime;
|
||||
public long noPwnageLastWarningTime;
|
||||
public long noPwnageLeaveTime;
|
||||
public int noPwnageReloginWarnings;
|
||||
@ -89,7 +88,7 @@ public class ChatData extends AsyncCheckData {
|
||||
// colorVL <- is spared to avoid problems with spam + captcha success.
|
||||
noPwnageVL = 0;
|
||||
noPwnageSpeed.clear(System.currentTimeMillis());
|
||||
noPwnageJoinTime = noPwnageLastMessageTime = noPwnageLastMovedTime = noPwnageLastWarningTime = noPwnageLeaveTime = noPwnageReloginWarningTime = 0L;
|
||||
noPwnageJoinTime = noPwnageLastMessageTime = noPwnageLastWarningTime = noPwnageLeaveTime = noPwnageReloginWarningTime = 0L;
|
||||
noPwnageGeneratedCaptcha = noPwnageLastMessage = "";
|
||||
}
|
||||
|
||||
|
@ -10,7 +10,6 @@ import org.bukkit.event.player.PlayerChangedWorldEvent;
|
||||
import org.bukkit.event.player.PlayerCommandPreprocessEvent;
|
||||
import org.bukkit.event.player.PlayerLoginEvent;
|
||||
import org.bukkit.event.player.PlayerLoginEvent.Result;
|
||||
import org.bukkit.event.player.PlayerMoveEvent;
|
||||
|
||||
import fr.neatmonster.nocheatplus.checks.CheckType;
|
||||
import fr.neatmonster.nocheatplus.command.INotifyReload;
|
||||
@ -204,28 +203,6 @@ public class ChatListener implements Listener, INotifyReload {
|
||||
event.disallow(Result.KICK_OTHER, cc.noPwnageReloginKickMessage);
|
||||
}
|
||||
|
||||
/**
|
||||
* When a player moves, he will be checked for various suspicious behaviors.
|
||||
*
|
||||
* @param event
|
||||
* the event
|
||||
*/
|
||||
@EventHandler(
|
||||
ignoreCancelled = true, priority = EventPriority.LOWEST)
|
||||
public void onPlayerMove(final PlayerMoveEvent event) {
|
||||
/*
|
||||
* _____ _ __ __
|
||||
* | __ \| | | \/ |
|
||||
* | |__) | | __ _ _ _ ___ _ __ | \ / | _____ _____
|
||||
* | ___/| |/ _` | | | |/ _ \ '__| | |\/| |/ _ \ \ / / _ \
|
||||
* | | | | (_| | |_| | __/ | | | | | (_) \ V / __/
|
||||
* |_| |_|\__,_|\__, |\___|_| |_| |_|\___/ \_/ \___|
|
||||
* __/ |
|
||||
* |___/
|
||||
*/
|
||||
ChatData.getData(event.getPlayer()).noPwnageLastMovedTime = System.currentTimeMillis();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onReload() {
|
||||
// Read some things from the global config file.
|
||||
|
@ -10,6 +10,7 @@ import fr.neatmonster.nocheatplus.actions.ParameterName;
|
||||
import fr.neatmonster.nocheatplus.checks.AsyncCheck;
|
||||
import fr.neatmonster.nocheatplus.checks.CheckType;
|
||||
import fr.neatmonster.nocheatplus.checks.ViolationData;
|
||||
import fr.neatmonster.nocheatplus.checks.combined.CombinedData;
|
||||
import fr.neatmonster.nocheatplus.players.Permissions;
|
||||
import fr.neatmonster.nocheatplus.utilities.CheckUtils;
|
||||
|
||||
@ -161,7 +162,7 @@ public class NoPwnage extends AsyncCheck implements ICaptcha{
|
||||
|
||||
// NoPwnage will check if a player moved within the "timeout" timeframe. If he did not move, the suspicion will
|
||||
// be increased by "weight" value.
|
||||
if (!isCommand && cc.noPwnageMoveCheck && now - data.noPwnageLastMovedTime > cc.noPwnageMoveTimeout)
|
||||
if (!isCommand && cc.noPwnageMoveCheck && now - CombinedData.getData(player).lastMoveTime > cc.noPwnageMoveTimeout)
|
||||
suspicion += cc.noPwnageMoveWeight;
|
||||
|
||||
// Should a player that reaches the "warnLevel" get a text message telling him that he is under suspicion of
|
||||
|
@ -41,7 +41,7 @@ public class Combined {
|
||||
* @param worldName
|
||||
* @param data
|
||||
*/
|
||||
private static final void feedYawRate(final Player player, final float yaw, final long now, final String worldName, final CombinedData data) {
|
||||
public static final void feedYawRate(final Player player, final float yaw, final long now, final String worldName, final CombinedData data) {
|
||||
// Reset on world change or timeout.
|
||||
if (now - data.lastYawTime > 999 || !worldName.equals(data.lastWorld)){
|
||||
data.lastYaw = yaw;
|
||||
@ -70,7 +70,7 @@ public class Combined {
|
||||
* @param worldName
|
||||
* @return
|
||||
*/
|
||||
private static final boolean checkYawRate(Player player, float yaw, long now, final String worldName, final CombinedData data) {
|
||||
public static final boolean checkYawRate(final Player player, final float yaw, final long now, final String worldName, final CombinedData data) {
|
||||
|
||||
feedYawRate(player, yaw, now, worldName, data);
|
||||
|
||||
|
@ -54,6 +54,8 @@ public class CombinedData extends ACheckData {
|
||||
|
||||
public String lastWorld = "";
|
||||
|
||||
public long lastMoveTime;
|
||||
|
||||
public CombinedData(final Player player){
|
||||
// final CombinedConfig cc = CombinedConfig.getConfig(player);
|
||||
// TODO: Get some things from the config.
|
||||
|
@ -36,12 +36,15 @@ public class CombinedListener implements Listener {
|
||||
|
||||
@EventHandler(priority=EventPriority.MONITOR, ignoreCancelled = false)
|
||||
public final void onPlayerMove(final PlayerMoveEvent event){
|
||||
// Experimental
|
||||
final long now = System.currentTimeMillis();
|
||||
final Player player = event.getPlayer();
|
||||
// Just add the yaw to the list.
|
||||
|
||||
final Location loc = player.getLocation();
|
||||
final String worldName = loc.getWorld().getName();
|
||||
Combined.feedYawRate(player, loc.getYaw(), System.currentTimeMillis(), worldName);
|
||||
final CombinedData data = CombinedData.getData(player);
|
||||
data.lastMoveTime = now;
|
||||
// Just add the yaw to the list.
|
||||
Combined.feedYawRate(player, loc.getYaw(), now, worldName, data);
|
||||
}
|
||||
|
||||
// (possibly other types of events, but these combine with fighting).
|
||||
|
@ -1,11 +1,10 @@
|
||||
package fr.neatmonster.nocheatplus.checks.moving;
|
||||
|
||||
import net.minecraft.server.Block;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.GameMode;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.entity.Vehicle;
|
||||
import org.bukkit.event.EventHandler;
|
||||
@ -29,6 +28,7 @@ import org.bukkit.util.Vector;
|
||||
|
||||
import fr.neatmonster.nocheatplus.NoCheatPlus;
|
||||
import fr.neatmonster.nocheatplus.players.Permissions;
|
||||
import fr.neatmonster.nocheatplus.utilities.BlockProperties;
|
||||
|
||||
/*
|
||||
* M"""""`'"""`YM oo
|
||||
@ -58,18 +58,6 @@ public class MovingListener implements Listener {
|
||||
/** The no fall check. **/
|
||||
public final static NoFall noFall = new NoFall();
|
||||
|
||||
/**
|
||||
* Checks if a material is liquid.
|
||||
*
|
||||
* @param material
|
||||
* the material
|
||||
* @return true, if the material is liquid
|
||||
*/
|
||||
public static boolean isLiquid(final Material material) {
|
||||
return material == Material.LAVA || material == Material.STATIONARY_LAVA
|
||||
|| material == Material.STATIONARY_WATER || material == Material.WATER;
|
||||
}
|
||||
|
||||
/** The instance of NoCheatPlus. */
|
||||
private final NoCheatPlus plugin = (NoCheatPlus) Bukkit.getPluginManager().getPlugin(
|
||||
"NoCheatPlus");
|
||||
@ -110,27 +98,40 @@ public class MovingListener implements Listener {
|
||||
*/
|
||||
final Player player = event.getPlayer();
|
||||
|
||||
// Ignore players inside a vehicle.
|
||||
if (player.isInsideVehicle())
|
||||
return;
|
||||
// Ignore players inside a vehicle.
|
||||
if (player.isInsideVehicle())
|
||||
return;
|
||||
|
||||
final MovingData data = MovingData.getData(player);
|
||||
final MovingData data = MovingData.getData(player);
|
||||
|
||||
final int blockY = event.getBlock().getY();
|
||||
if (isLiquid(event.getBlockAgainst().getType()) && event.getBlock().getType() != Material.WATER_LILY)
|
||||
// The block was placed against a liquid block, cancel its placement.
|
||||
event.setCancelled(true);
|
||||
else if ((creativeFly.isEnabled(player) || survivalFly.isEnabled(player)) && event.getBlock() != null
|
||||
&& data.setBack != null && blockY + 1D >= data.setBack.getY()
|
||||
&& Math.abs(player.getLocation().getX() - 0.5 - event.getBlock().getX()) <= 1D
|
||||
&& Math.abs(player.getLocation().getZ() - 0.5 - event.getBlock().getZ()) <= 1D
|
||||
&& player.getLocation().getY() - blockY > 0D && player.getLocation().getY() - blockY < 2D
|
||||
&& (Block.i(event.getBlock().getTypeId()) || isLiquid(event.getBlock().getType()))) {
|
||||
// The creative fly and/or survival fly check is enabled, the block was placed below the player and is
|
||||
// solid, so do what we have to do.
|
||||
data.setBack.setY(blockY + 1D);
|
||||
data.survivalFlyJumpPhase = 0;
|
||||
}
|
||||
final org.bukkit.block.Block block = event.getBlock();
|
||||
final int blockY = block.getY();
|
||||
|
||||
final Material mat = block.getType();
|
||||
|
||||
if (BlockProperties.isLiquid(event.getBlockAgainst().getTypeId())
|
||||
&& mat != Material.WATER_LILY)
|
||||
// The block was placed against a liquid block, cancel its
|
||||
// placement.
|
||||
event.setCancelled(true);
|
||||
else {
|
||||
|
||||
if (!creativeFly.isEnabled(player) && !survivalFly.isEnabled(player)) return;
|
||||
|
||||
if (block == null || data.setBack == null || blockY + 1D < data.setBack.getY()) return;
|
||||
|
||||
final Location loc = player.getLocation();
|
||||
if (Math.abs(loc.getX() - 0.5 - block.getX()) <= 1D
|
||||
&& Math.abs(loc.getZ() - 0.5 - block.getZ()) <= 1D
|
||||
&& loc.getY() - blockY > 0D && loc.getY() - blockY < 2D
|
||||
&& (BlockProperties.i(mat.getId()) || BlockProperties.isLiquid(mat.getId()))) {
|
||||
// The creative fly and/or survival fly check is enabled, the
|
||||
// block was placed below the player and is
|
||||
// solid, so do what we have to do.
|
||||
data.setBack.setY(blockY + 1D);
|
||||
data.survivalFlyJumpPhase = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -248,15 +249,24 @@ public class MovingListener implements Listener {
|
||||
* |_| |_|\__,_|\__, |\___|_| |___|_| |_|\__\___|_| \__,_|\___|\__|
|
||||
* |___/
|
||||
*/
|
||||
if (!event.getPlayer().hasPermission(Permissions.MOVING_BOATSANYWHERE)
|
||||
&& event.getAction() == Action.RIGHT_CLICK_BLOCK
|
||||
&& event.getPlayer().getItemInHand().getType() == Material.BOAT
|
||||
&& event.getClickedBlock().getType() != Material.WATER
|
||||
&& event.getClickedBlock().getType() != Material.STATIONARY_WATER
|
||||
&& event.getClickedBlock().getRelative(event.getBlockFace()).getType() != Material.WATER
|
||||
&& event.getClickedBlock().getRelative(event.getBlockFace()).getType() != Material.STATIONARY_WATER)
|
||||
// If the player right clicked on a non-liquid block with a boat in his hands, cancel the event.
|
||||
event.setCancelled(true);
|
||||
// If the player right clicked on a non-liquid block with a boat in his hands, cancel the event.
|
||||
if (event.getAction() != Action.RIGHT_CLICK_BLOCK) return;
|
||||
|
||||
final Player player = event.getPlayer();
|
||||
if (player.getItemInHand().getType() != Material.BOAT) return;
|
||||
if (event.getPlayer().hasPermission(Permissions.MOVING_BOATSANYWHERE)) return;
|
||||
|
||||
final org.bukkit.block.Block block = event.getClickedBlock();
|
||||
final Material mat = block.getType();
|
||||
|
||||
if (mat == Material.WATER || mat == Material.STATIONARY_WATER) return;
|
||||
|
||||
final org.bukkit.block.Block relBlock = block.getRelative(event.getBlockFace());
|
||||
final Material relMat = relBlock.getType();
|
||||
|
||||
if (relMat == Material.WATER || relMat == Material.STATIONARY_WATER) return;
|
||||
|
||||
event.setCancelled(true);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -503,11 +513,14 @@ public class MovingListener implements Listener {
|
||||
* \ V / __/ | | | | (__| | __/ | | | | (_) \ V / __/
|
||||
* \_/ \___|_| |_|_|\___|_|\___| |_| |_|\___/ \_/ \___|
|
||||
*/
|
||||
final Vehicle vehicle = event.getVehicle();
|
||||
final Entity passenger = vehicle.getPassenger();
|
||||
// Don't care if a player isn't inside the vehicle, for movements that are very high distance or to another
|
||||
// world (such that it is very likely the event data was modified by another plugin before we got it).
|
||||
if (event.getVehicle().getPassenger() == null || !(event.getVehicle().getPassenger() instanceof Player)
|
||||
|| !event.getFrom().getWorld().equals(event.getTo().getWorld()))
|
||||
return;
|
||||
if (passenger == null || !(passenger instanceof Player)) return;
|
||||
final Location from = event.getFrom();
|
||||
final Location to = event.getTo();
|
||||
if (!from.getWorld().equals(to.getWorld())) return;
|
||||
|
||||
final Player player = (Player) event.getVehicle().getPassenger();
|
||||
|
||||
@ -515,7 +528,7 @@ public class MovingListener implements Listener {
|
||||
|
||||
if (morePacketsVehicle.isEnabled(player))
|
||||
// If the player is handled by the more packets vehicle check, execute it.
|
||||
newTo = morePacketsVehicle.check(player, event.getFrom(), event.getTo());
|
||||
newTo = morePacketsVehicle.check(player, from, to);
|
||||
else
|
||||
// Otherwise we need to clear his data.
|
||||
MovingData.getData(player).clearMorePacketsData();
|
||||
@ -538,6 +551,6 @@ public class MovingListener implements Listener {
|
||||
this.location = location;
|
||||
return this;
|
||||
}
|
||||
}.set(event.getVehicle(), newTo), 1L);
|
||||
}.set(vehicle, newTo), 1L);
|
||||
}
|
||||
}
|
||||
|
@ -15,6 +15,7 @@ import fr.neatmonster.nocheatplus.checks.Check;
|
||||
import fr.neatmonster.nocheatplus.checks.CheckType;
|
||||
import fr.neatmonster.nocheatplus.checks.ViolationData;
|
||||
import fr.neatmonster.nocheatplus.players.Permissions;
|
||||
import fr.neatmonster.nocheatplus.utilities.BlockProperties;
|
||||
import fr.neatmonster.nocheatplus.utilities.PlayerLocation;
|
||||
|
||||
/*
|
||||
@ -134,17 +135,19 @@ public class SurvivalFly extends Check {
|
||||
// Prevent players from walking on a liquid.
|
||||
// TODO: yDistance == 0D <- should there not be a tolerance +- or 0...x ?
|
||||
if (hDistanceAboveLimit <= 0D && hDistance > 0.1D && yDistance == 0D
|
||||
&& MovingListener.isLiquid(to.getLocation().getBlock().getType()) && !to.isOnGround()
|
||||
&& BlockProperties.isLiquid(to.getTypeId()) && !to.isOnGround()
|
||||
&& to.getY() % 1D < 0.8D)
|
||||
hDistanceAboveLimit = hDistance;
|
||||
|
||||
// Prevent players from sprinting if they're moving backwards.
|
||||
if (hDistanceAboveLimit <= 0D && sprinting && !player.hasPermission(Permissions.MOVING_SURVIVALFLY_SPRINTING)) {
|
||||
if (hDistanceAboveLimit <= 0D && sprinting) {
|
||||
final float yaw = from.getYaw();
|
||||
if (xDistance < 0D && zDistance > 0D && yaw > 180F && yaw < 270F || xDistance < 0D && zDistance < 0D
|
||||
&& yaw > 270F && yaw < 360F || xDistance > 0D && zDistance < 0D && yaw > 0F && yaw < 90F
|
||||
|| xDistance > 0D && zDistance > 0D && yaw > 90F && yaw < 180F)
|
||||
hDistanceAboveLimit = hDistance;
|
||||
|| xDistance > 0D && zDistance > 0D && yaw > 90F && yaw < 180F){
|
||||
// Assumes permission check to be the heaviest (might be mistaken).
|
||||
if (!player.hasPermission(Permissions.MOVING_SURVIVALFLY_SPRINTING)) hDistanceAboveLimit = hDistance;
|
||||
}
|
||||
}
|
||||
|
||||
data.bunnyhopDelay--;
|
||||
|
@ -6,6 +6,8 @@ import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import net.minecraft.server.Block;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
@ -231,6 +233,12 @@ public class BlockProperties {
|
||||
Material.CROPS,
|
||||
};
|
||||
|
||||
protected static final long[] blockFlags = new long[maxBlocks];
|
||||
|
||||
/** Flag position for stairs. */
|
||||
public static final int F_STAIRS = 0x1;
|
||||
public static final int F_LIQUID = 0x2;
|
||||
|
||||
static{
|
||||
try{
|
||||
initTools();
|
||||
@ -272,10 +280,24 @@ public class BlockProperties {
|
||||
|
||||
|
||||
private static void initBlocks() {
|
||||
for (int i = 0; i <blocks.length; i++){
|
||||
for (int i = 0; i <maxBlocks; i++){
|
||||
blocks[i] = null;
|
||||
blockFlags[i] = 0;
|
||||
}
|
||||
//
|
||||
// Stairs.
|
||||
for (final Material mat : new Material[] {Material.WOOD_STAIRS, Material.COBBLESTONE_STAIRS,
|
||||
Material.BRICK_STAIRS, Material.SMOOTH_STAIRS, Material.NETHER_BRICK_STAIRS, Material.SANDSTONE_STAIRS,
|
||||
Material.SPRUCE_WOOD_STAIRS, Material.BIRCH_WOOD_STAIRS, Material.JUNGLE_WOOD_STAIRS}){
|
||||
blockFlags[mat.getId()] |= F_STAIRS;
|
||||
}
|
||||
// Liquid.
|
||||
for (final Material mat : new Material[]{
|
||||
Material.LAVA, Material.STATIONARY_LAVA,
|
||||
Material.STATIONARY_WATER, Material.WATER,
|
||||
}) {
|
||||
blockFlags[mat.getId()] |= F_LIQUID;
|
||||
}
|
||||
// Instantly breakable.
|
||||
for (final Material mat : instantMat){
|
||||
blocks[mat.getId()] = instantType;
|
||||
}
|
||||
@ -702,4 +724,24 @@ public class BlockProperties {
|
||||
blockProps.validate();
|
||||
BlockProperties.defaultBlockProps = blockProps;
|
||||
}
|
||||
|
||||
/**
|
||||
* Hiding the API access here.<br>
|
||||
* TODO: Find description of this and use block properties from here, as well as a speaking method name.
|
||||
* @param id
|
||||
* @return
|
||||
*/
|
||||
public static final boolean i(final int id) {
|
||||
return Block.i(id);
|
||||
}
|
||||
|
||||
|
||||
public static final boolean isStairs(final int id) {
|
||||
return (blockFlags[id] & F_STAIRS) != 0;
|
||||
}
|
||||
|
||||
|
||||
public static boolean isLiquid(final int id) {
|
||||
return (blockFlags[id] & F_LIQUID) != 0;
|
||||
}
|
||||
}
|
||||
|
@ -1,14 +1,11 @@
|
||||
package fr.neatmonster.nocheatplus.utilities;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import net.minecraft.server.AxisAlignedBB;
|
||||
import net.minecraft.server.Block;
|
||||
import net.minecraft.server.EntityPlayer;
|
||||
import net.minecraft.server.WorldServer;
|
||||
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.craftbukkit.CraftWorld;
|
||||
import org.bukkit.craftbukkit.entity.CraftPlayer;
|
||||
import org.bukkit.entity.Player;
|
||||
@ -36,10 +33,12 @@ import org.bukkit.entity.Player;
|
||||
*/
|
||||
public class PlayerLocation {
|
||||
|
||||
private static final Material[] STAIRS = new Material[] {Material.WOOD_STAIRS, Material.COBBLESTONE_STAIRS,
|
||||
Material.BRICK_STAIRS, Material.SMOOTH_STAIRS, Material.NETHER_BRICK_STAIRS, Material.SANDSTONE_STAIRS,
|
||||
Material.SPRUCE_WOOD_STAIRS, Material.BIRCH_WOOD_STAIRS, Material.JUNGLE_WOOD_STAIRS};
|
||||
|
||||
/** Type id of the block at the position. */
|
||||
private Integer typeId;
|
||||
|
||||
/** Type id of the block below. */
|
||||
private Integer typeIdBelow;
|
||||
|
||||
/** The original location. */
|
||||
private Location location;
|
||||
|
||||
@ -140,7 +139,7 @@ public class PlayerLocation {
|
||||
*/
|
||||
public boolean isAboveStairs() {
|
||||
if (aboveStairs == null)
|
||||
aboveStairs = Arrays.asList(STAIRS).contains(Material.getMaterial(world.getTypeId(x, y - 1, z)));
|
||||
aboveStairs = BlockProperties.isStairs(getTypeIdBelow().intValue());
|
||||
return aboveStairs;
|
||||
}
|
||||
|
||||
@ -227,7 +226,7 @@ public class PlayerLocation {
|
||||
if (entity.getBukkitEntity().isSneaking() || entity.getBukkitEntity().isBlocking())
|
||||
onIce = world.getTypeId(x, (int) Math.floor(boundingBox.b - 0.1D), z) == Block.ICE.id;
|
||||
else
|
||||
onIce = world.getTypeId(x, y - 1, z) == Block.ICE.id;
|
||||
onIce = getTypeIdBelow() == Block.ICE.id;
|
||||
return onIce;
|
||||
}
|
||||
|
||||
@ -237,8 +236,10 @@ public class PlayerLocation {
|
||||
* @return true, if the player is on a ladder
|
||||
*/
|
||||
public boolean isOnLadder() {
|
||||
if (onLadder == null)
|
||||
onLadder = world.getTypeId(x, y, z) == Block.LADDER.id || world.getTypeId(x, y, z) == Block.VINE.id;
|
||||
if (onLadder == null){
|
||||
final int typeId = getTypeId();
|
||||
onLadder = typeId == Block.LADDER.id || typeId == Block.VINE.id;
|
||||
}
|
||||
return onLadder;
|
||||
}
|
||||
|
||||
@ -286,4 +287,16 @@ public class PlayerLocation {
|
||||
this.yOnGround = yOnGround;
|
||||
this.onGround = null;
|
||||
}
|
||||
|
||||
public Integer getTypeId() {
|
||||
if (typeId == null) typeId = world.getTypeId(x, y, z);
|
||||
return typeId;
|
||||
}
|
||||
|
||||
|
||||
public Integer getTypeIdBelow() {
|
||||
if (typeIdBelow == null) typeIdBelow = world.getTypeId(x, y - 1, z);
|
||||
return typeIdBelow;
|
||||
}
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user