Merge pull request #1 from NoCheatPlus/master

Upstream merge
This commit is contained in:
MyPictures 2014-07-15 22:29:06 +02:00
commit 7e931c8d2e
131 changed files with 4464 additions and 1154 deletions

View File

@ -0,0 +1,19 @@
package fr.neatmonster.nocheatplus.time;
/**
* Some kind of clock.
*
* @author mc_dev
*
*/
public interface Clock {
/**
* Get the clock counter. There is no guarantee that this is monotonic, nor
* need it be thread-safe.
*
* @return
*/
public long clock();
}

View File

@ -0,0 +1,58 @@
package fr.neatmonster.nocheatplus.time.monotonic;
/**
* Static provider for monotonic clocks. Note that some calls can only be made
* from the server/application main thread, thread safe methods are prefixed
* with "synch", however all call results may have different offsets.
*/
public class Monotonic {
private static final MonotonicClock nanos = new MonotonicNanosClock();
private static final MonotonicClock millis = new MonotonicMillisClock();
private static final MonotonicClock synchMillis = new MonotonicSynchClock(new MonotonicMillisClock());
private static final MonotonicClock synchNanos = new MonotonicSynchClock(new MonotonicNanosClock());
/**
* Monotonic nanoseconds time, corresponding to System.nanoTime(). <br>
* <b>Not thread-safe, only call from the main server/application
* thread.</b>
*
* @return Monotonic time in nanoseconds.
*/
public static long nanos() {
return nanos.clock();
}
/**
* Monotonic milliseconds time, corresponding to System.currentTimeMillis(). <br>
* <b>Not thread-safe, only call from the main server/application
* thread.</b>
*
* @return Monotonic time in milliseconds.
*/
public static long millis() {
return millis.clock();
}
/**
* Monotonic nanoseconds time, corresponding to System.nanoTime(). <br>
* Thread-safe.
*
* @return Monotonic time in nanoseconds.
*/
public static long synchNanos() {
return synchNanos.clock();
}
/**
* Monotonic milliseconds time, corresponding to System.currentTimeMillis(). <br>
* Thread-safe.
*
* @return Monotonic time in milliseconds.
*/
public static long synchMillis() {
return synchMillis.clock();
}
}

View File

@ -0,0 +1,43 @@
package fr.neatmonster.nocheatplus.time.monotonic;
/**
* Basic implementation of increasing a counter for a not necessarily monotonic
* underlying clock, fetched with fetchClock(). Not thread-safe.
*
*/
public abstract class MonotonicAbstractClock implements MonotonicClock {
private long clock;
private long lastFetch;
public MonotonicAbstractClock() {
clock = fetchClock();
lastFetch = clock;
}
public MonotonicAbstractClock(long clock) {
reset(clock);
}
protected abstract long fetchClock();
@Override
public long clock() {
// TODO: Add feature to detect running too fast and correction as well.
final long fetch = fetchClock();
final long diff = fetch - this.lastFetch;
if (diff > 0) {
this.clock += diff;
}
this.lastFetch = fetch;
return this.clock;
}
@Override
public void reset(long clock) {
this.clock = clock;
this.lastFetch = fetchClock();
}
}

View File

@ -0,0 +1,19 @@
package fr.neatmonster.nocheatplus.time.monotonic;
import fr.neatmonster.nocheatplus.time.Clock;
/**
* Monotonic clock. The clock() method will count since creation or call of
* reset, unless stated otherwise.
*
* @author mc_dev
*
*/
public interface MonotonicClock extends Clock {
/**
* Monotonic clock allow resetting for some reason.
*/
public void reset(long clock);
}

View File

@ -0,0 +1,16 @@
package fr.neatmonster.nocheatplus.time.monotonic;
/**
* Monotonic clock based on System.currentTimeMillis(). Not thread-safe.
*
* @author mc_dev
*
*/
public class MonotonicMillisClock extends MonotonicAbstractClock {
@Override
protected long fetchClock() {
return System.currentTimeMillis();
}
}

View File

@ -0,0 +1,16 @@
package fr.neatmonster.nocheatplus.time.monotonic;
/**
* Monotonic clock based on System.nanoTime(). Not thread-safe.
*
* @author mc_dev
*
*/
public class MonotonicNanosClock extends MonotonicAbstractClock {
@Override
protected long fetchClock() {
return System.nanoTime();
}
}

View File

@ -0,0 +1,29 @@
package fr.neatmonster.nocheatplus.time.monotonic;
/**
* Thread safe version of a monotonic clock, wrapping around a given clock.
* Since synchronized method bodies wrap around the underlying clock, the clock
* must not be used outside of this instance.
*
* @author mc_dev
*
*/
public class MonotonicSynchClock implements MonotonicClock {
private final MonotonicClock clock;
public MonotonicSynchClock(MonotonicClock clock) {
this.clock = clock;
}
@Override
public synchronized long clock() {
return clock.clock();
}
@Override
public synchronized void reset(long clock) {
this.clock.reset(clock);
}
}

View File

@ -0,0 +1,6 @@
/**
* Provides monotonic clocks. [Taken from NC4 Planning/Framework.]
* @author mc_dev
*
*/
package fr.neatmonster.nocheatplus.time.monotonic;

View File

@ -0,0 +1,4 @@
/**
* Time related functionality. [Taken from NC4 Planning/Framework.]
*/
package fr.neatmonster.nocheatplus.time;

View File

@ -109,7 +109,7 @@ public class CharPrefixTree<N extends CharNode<N>, L extends CharLookupEntry<N>>
/**
* Test hasPrefixWords for each given argument.
* @param inputs
* @return true if hasPrefixWords returns ture for any of the inputs, false otherwise.
* @return true if hasPrefixWords(String) returns true for any of the inputs, false otherwise.
*/
public boolean hasAnyPrefixWords(final String... inputs){
for (int i = 0; i < inputs.length; i++){
@ -120,6 +120,20 @@ public class CharPrefixTree<N extends CharNode<N>, L extends CharLookupEntry<N>>
return false;
}
/**
* Test hasPrefixWords for each element of the collection.
* @param inputs
* @return true if hasPrefixWords(String) returns true for any of the elements, false otherwise.
*/
public boolean hasAnyPrefixWords(final Collection<String> inputs){
for (final String input : inputs){
if (hasPrefixWords(input)){
return true;
}
}
return false;
}
public boolean isPrefix(final char[] chars){
return isPrefix(toCharacterList(chars));
}

View File

@ -12,6 +12,7 @@ import fr.neatmonster.nocheatplus.actions.ParameterName;
import fr.neatmonster.nocheatplus.checks.Check;
import fr.neatmonster.nocheatplus.checks.CheckType;
import fr.neatmonster.nocheatplus.checks.ViolationData;
import fr.neatmonster.nocheatplus.compat.BridgeHealth;
import fr.neatmonster.nocheatplus.config.ConfPaths;
import fr.neatmonster.nocheatplus.config.ConfigManager;
import fr.neatmonster.nocheatplus.logging.LogUtil;
@ -44,26 +45,35 @@ public class FastConsume extends Check implements Listener{
@EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true)
public void onItemConsume(final PlayerItemConsumeEvent event){
final Player player = event.getPlayer();
if (!isEnabled(player)) return;
if (player.isDead() && BridgeHealth.getHealth(player) <= 0.0) {
// Eat after death.
event.setCancelled(true);
return;
}
if (!isEnabled(player)) {
return;
}
final InventoryData data = InventoryData.getData(player);
if (check(player, event.getItem(), data)){
final long time = System.currentTimeMillis();
if (check(player, event.getItem(), time, data)){
event.setCancelled(true);
DataManager.getPlayerData(player.getName(), true).task.updateInventory();
}
data.instantEatInteract = 0;
data.instantEatInteract = time;
data.instantEatFood = null;
}
private boolean check(final Player player, final ItemStack stack, final InventoryData data){
private boolean check(final Player player, final ItemStack stack, final long time, final InventoryData data){
// Uses the instant-eat data for convenience.
// Consistency checks...
if (stack == null){ // || stack.getType() != data.instantEatFood){
// TODO: Strict version should prevent other material (?).
return false;
}
final long time = System.currentTimeMillis();
final long ref = Math.max(data.instantEatInteract, data.lastClickTime);
final long ref = data.instantEatInteract == 0 ? 0 : Math.max(data.instantEatInteract, data.lastClickTime);
if (time < ref){
// Time ran backwards.
data.instantEatInteract = data.lastClickTime = time;
return false;
}
// Check exceptions.
@ -71,11 +81,11 @@ public class FastConsume extends Check implements Listener{
final Material mat = stack == null ? null : stack.getType();
if (mat != null){
if (cc.fastConsumeWhitelist){
if (!cc.fastConsumeItems.contains(mat.getId())){
if (!cc.fastConsumeItems.contains(mat)){
return false;
}
}
else if (cc.fastConsumeItems.contains(mat.getId())){
else if (cc.fastConsumeItems.contains(mat)){
return false;
}
}

View File

@ -11,6 +11,9 @@ public class BlockCacheBukkit extends BlockCache{
protected World world;
/** Temporary use. Use LocUtil.clone before passing on. Call setWorld(null) after use. */
protected final Location useLoc = new Location(null, 0, 0, 0);
public BlockCacheBukkit(World world) {
setAccess(world);
}
@ -18,14 +21,19 @@ public class BlockCacheBukkit extends BlockCache{
@Override
public void setAccess(World world) {
this.world = world;
if (world != null) {
this.maxBlockY = world.getMaxHeight() - 1;
}
}
@SuppressWarnings("deprecation")
@Override
public int fetchTypeId(final int x, final int y, final int z) {
// TODO: consider setting type id and data at once.
return world.getBlockTypeIdAt(x, y, z);
}
@SuppressWarnings("deprecation")
@Override
public int fetchData(final int x, final int y, final int z) {
// TODO: consider setting type id and data at once.
@ -49,8 +57,9 @@ public class BlockCacheBukkit extends BlockCache{
if (type != EntityType.BOAT){ // && !(other instanceof Minecart))
continue;
}
final Location loc = entity.getLocation();
if (Math.abs(loc.getY() - minY) < 0.7){
final double locY = entity.getLocation(useLoc).getY();
useLoc.setWorld(null);
if (Math.abs(locY - minY) < 0.7){
// TODO: A "better" estimate is possible, though some more tolerance would be good.
return true;
}

View File

@ -28,10 +28,12 @@ import fr.neatmonster.nocheatplus.utilities.ReflectionUtil;
public class MCAccessBukkit implements MCAccess, BlockPropertiesSetup{
// private AlmostBoolean entityPlayerAvailable = AlmostBoolean.MAYBE;
/**
* Constructor to let it fail.
*/
public MCAccessBukkit(){
public MCAccessBukkit() {
// TODO: Add more that might fail if not supported ?
Material.AIR.isSolid();
Material.AIR.isOccluding();
@ -43,7 +45,7 @@ public class MCAccessBukkit implements MCAccess, BlockPropertiesSetup{
public String getMCVersion() {
// Bukkit API.
// TODO: maybe output something else.
return "1.4.6|1.4.7|1.5.x|1.6.1|1.6.2|?";
return "1.4.6|1.4.7|1.5.x|1.6.x|1.7.x"; // 1.7.x is bold!
}
@Override
@ -55,7 +57,7 @@ public class MCAccessBukkit implements MCAccess, BlockPropertiesSetup{
public CommandMap getCommandMap() {
try{
return (CommandMap) ReflectionUtil.invokeMethodNoArgs(Bukkit.getServer(), "getCommandMap");
} catch (Throwable t){
} catch (Throwable t) {
// Nasty.
return null;
}
@ -76,13 +78,19 @@ public class MCAccessBukkit implements MCAccess, BlockPropertiesSetup{
@Override
public AlmostBoolean isBlockSolid(final int id) {
@SuppressWarnings("deprecation")
final Material mat = Material.getMaterial(id);
if (mat == null) return AlmostBoolean.MAYBE;
else return AlmostBoolean.match(mat.isSolid());
if (mat == null) {
return AlmostBoolean.MAYBE;
}
else {
return AlmostBoolean.match(mat.isSolid());
}
}
@Override
public AlmostBoolean isBlockLiquid(final int id) {
@SuppressWarnings("deprecation")
final Material mat = Material.getMaterial(id);
if (mat == null) return AlmostBoolean.MAYBE;
switch (mat) {
@ -104,8 +112,10 @@ public class MCAccessBukkit implements MCAccess, BlockPropertiesSetup{
@Override
public AlmostBoolean isIllegalBounds(final Player player) {
if (player.isDead()) return AlmostBoolean.NO;
if (!player.isSleeping()){ // TODO: ignored sleeping ?
if (player.isDead()) {
return AlmostBoolean.NO;
}
if (!player.isSleeping()) { // TODO: ignored sleeping ?
// TODO: This can test like ... nothing !
// (Might not be necessary.)
}
@ -161,40 +171,43 @@ public class MCAccessBukkit implements MCAccess, BlockPropertiesSetup{
// TODO: Might try stuff like setNoDamageTicks.
BridgeHealth.damage(player, 1.0);
}
@Override
public void setupBlockProperties(final WorldConfigProvider<?> worldConfigProvider) {
// Note deprecation suppression: These ids should be unique for a server run, that should be ok for setting up generic properties.
// TODO: (?) Set some generic properties matching what BlockCache.getShape returns.
final Set<Integer> fullBlocks = new HashSet<Integer>();
final Set<Material> fullBlocks = new HashSet<Material>();
for (final Material mat : new Material[]{
// TODO: Ice !? / Packed ice !?
Material.GLASS, Material.GLOWSTONE, Material.ICE, Material.LEAVES,
Material.COMMAND, Material.BEACON,
Material.PISTON_BASE,
}){
fullBlocks.add(mat.getId());
}) {
fullBlocks.add(mat);
}
for (final Material mat : Material.values()){
if (!mat.isBlock()) continue;
final int id = mat.getId();
if (id < 0 || id >= 4096 || fullBlocks.contains(id)) continue;
if (!mat.isOccluding() || !mat.isSolid() || mat.isTransparent()){
for (final Material mat : Material.values()) {
if (!mat.isBlock()) {
continue;
}
if (fullBlocks.contains(mat)) {
continue;
}
if (!mat.isOccluding() || !mat.isSolid() || mat.isTransparent()) {
// Uncertain bounding-box, allow passing through.
long flags = BlockProperties.F_IGN_PASSABLE;
if ((BlockProperties.isSolid(id) || BlockProperties.isGround(id)) && !BlockProperties.isLiquid(id)){
if ((BlockProperties.isSolid(mat) || BlockProperties.isGround(mat)) && !BlockProperties.isLiquid(mat)) {
// Block can be ground, so allow standing on any height.
flags |= BlockProperties.F_GROUND_HEIGHT;
}
BlockProperties.setBlockFlags(id, BlockProperties.getBlockFlags(id) | flags);
BlockProperties.setBlockFlags(mat, BlockProperties.getBlockFlags(mat) | flags);
}
}
// Blocks that are reported to be full and solid, but which are not.
for (final Material mat : new Material[]{
Material.ENDER_PORTAL_FRAME,
}){
final int id = mat.getId();
}) {
final long flags = BlockProperties.F_IGN_PASSABLE | BlockProperties.F_GROUND_HEIGHT;
BlockProperties.setBlockFlags(id, BlockProperties.getBlockFlags(id) | flags);
BlockProperties.setBlockFlags(mat, BlockProperties.getBlockFlags(mat) | flags);
}
}
@ -209,9 +222,9 @@ public class MCAccessBukkit implements MCAccess, BlockPropertiesSetup{
try{
return mat.hasGravity();
}
catch(Throwable t){
catch(Throwable t) {
// Backwards compatibility.
switch(mat){
switch(mat) {
case SAND:
case GRAVEL:
return true;
@ -220,5 +233,10 @@ public class MCAccessBukkit implements MCAccess, BlockPropertiesSetup{
}
}
}
// @Override
// public void correctDirection(Player player) {
// // TODO: Consider using reflection (detect CraftPlayer, access EntityPlayer + check if possible (!), use flags for if valid or invalid.)
// }
}

View File

@ -1,133 +0,0 @@
package fr.neatmonster.nocheatplus.compat.cb2511;
import java.util.Iterator;
import java.util.List;
import net.minecraft.server.AxisAlignedBB;
import net.minecraft.server.IBlockAccess;
import net.minecraft.server.Material;
import net.minecraft.server.TileEntity;
import net.minecraft.server.Vec3DPool;
import org.bukkit.World;
import org.bukkit.craftbukkit.CraftWorld;
import org.bukkit.craftbukkit.entity.CraftEntity;
import org.bukkit.entity.Entity;
import org.bukkit.entity.EntityType;
import fr.neatmonster.nocheatplus.utilities.BlockCache;
public class BlockCacheCB2511 extends BlockCache implements IBlockAccess{
/** Box for one time use, no nesting, no extra storing this(!). */
protected static final AxisAlignedBB useBox = AxisAlignedBB.a(0, 0, 0, 0, 0, 0);
protected net.minecraft.server.World world;
public BlockCacheCB2511(World world) {
setAccess(world);
}
@Override
public void setAccess(final World world) {
this.world = world == null ? null : ((CraftWorld) world).getHandle();
}
@Override
public int fetchTypeId(final int x, final int y, final int z) {
return world.getTypeId(x, y, z);
}
@Override
public int fetchData(final int x, final int y, final int z) {
return world.getData(x, y, z);
}
@Override
public double[] fetchBounds(final int x, final int y, final int z){
// TODO: change api for this / use nodes (!)
final int id = getTypeId(x, y, z);
final net.minecraft.server.Block block = net.minecraft.server.Block.byId[id];
if (block == null) return null;
block.updateShape(this, x, y, z); // TODO: use THIS instead of world.
// minX, minY, minZ, maxX, maxY, maxZ
return new double[]{block.v(), block.x(), block.z(), block.w(), block.y(), block.A()};
}
@Override
public boolean standsOnEntity(Entity entity, final double minX, final double minY, final double minZ, final double maxX, final double maxY, final double maxZ){
try{
// TODO: Probably check other ids too before doing this ?
final net.minecraft.server.Entity mcEntity = ((CraftEntity) entity).getHandle();
final AxisAlignedBB box = useBox.b(minX, minY, minZ, maxX, maxY, maxZ);
@SuppressWarnings("rawtypes")
final List list = world.getEntities(mcEntity, box);
@SuppressWarnings("rawtypes")
Iterator iterator = list.iterator();
while (iterator.hasNext()) {
final net.minecraft.server.Entity other = (net.minecraft.server.Entity) iterator.next();
final EntityType type = other.getBukkitEntity().getType();
if (type != EntityType.BOAT && type != EntityType.MINECART) continue;
final AxisAlignedBB otherBox = other.boundingBox;
if (box.a > otherBox.d || box.d < otherBox.a || box.b > otherBox.e || box.e < otherBox.b || box.c > otherBox.f || box.f < otherBox.c) continue;
else {
return true;
}
}
}
catch (Throwable t){
// Ignore exceptions (Context: DisguiseCraft).
}
return false;
}
/* (non-Javadoc)
* @see fr.neatmonster.nocheatplus.utilities.BlockCache#cleanup()
*/
@Override
public void cleanup() {
super.cleanup();
world = null;
}
@Override
public Material getMaterial(final int x, final int y, final int z) {
return world.getMaterial(x, y, z);
}
@Override
public TileEntity getTileEntity(final int x, final int y, final int z) {
return world.getTileEntity(x, y, z);
}
@Override
public Vec3DPool getVec3DPool() {
return world.getVec3DPool();
}
@Override
public boolean isBlockFacePowered(final int arg0, final int arg1, final int arg2, final int arg3) {
return world.isBlockFacePowered(arg0, arg1, arg2, arg3);
}
@Override
public boolean t(final int x, final int y, final int z) {
return world.t(x, y, z);
}
/**
* Compatibility with 1.4.2.
* @param x
* @param y
* @param z
* @return
*/
public boolean s(final int x, final int y, final int z) {
return world.t(x, y, z);
}
}

View File

@ -30,7 +30,12 @@ public class BlockCacheCB2512 extends BlockCache implements IBlockAccess{
@Override
public void setAccess(World world) {
this.world = world == null ? null : ((CraftWorld) world).getHandle();
if (world != null) {
this.maxBlockY = world.getMaxHeight() - 1;
this.world = ((CraftWorld) world).getHandle();
} else {
this.world = null;
}
}
@Override

View File

@ -99,7 +99,7 @@ public class MCAccessCB2512 implements MCAccess{
@Override
public double getJumpAmplifier(final Player player) {
final net.minecraft.server.v1_4_5.EntityPlayer mcPlayer = ((CraftPlayer) player).getHandle();
final EntityPlayer mcPlayer = ((CraftPlayer) player).getHandle();
if (mcPlayer.hasEffect(MobEffectList.JUMP)) return mcPlayer.getEffect(MobEffectList.JUMP).getAmplifier();
else return Double.NEGATIVE_INFINITY;
@ -107,7 +107,7 @@ public class MCAccessCB2512 implements MCAccess{
@Override
public double getFasterMovementAmplifier(final Player player) {
final net.minecraft.server.v1_4_5.EntityPlayer mcPlayer = ((CraftPlayer) player).getHandle();
final EntityPlayer mcPlayer = ((CraftPlayer) player).getHandle();
if (mcPlayer.hasEffect(MobEffectList.FASTER_MOVEMENT)) return mcPlayer.getEffect(MobEffectList.FASTER_MOVEMENT).getAmplifier();
else return Double.NEGATIVE_INFINITY;
}
@ -134,13 +134,13 @@ public class MCAccessCB2512 implements MCAccess{
@Override
public boolean shouldBeZombie(final Player player) {
final net.minecraft.server.v1_4_5.EntityPlayer mcPlayer = ((CraftPlayer) player).getHandle();
final EntityPlayer mcPlayer = ((CraftPlayer) player).getHandle();
return !mcPlayer.dead && mcPlayer.getHealth() <= 0 ;
}
@Override
public void setDead(final Player player, final int deathTicks) {
final net.minecraft.server.v1_4_5.EntityPlayer mcPlayer = ((CraftPlayer) player).getHandle();
final EntityPlayer mcPlayer = ((CraftPlayer) player).getHandle();
mcPlayer.deathTicks = deathTicks;
mcPlayer.dead = true;
}
@ -162,4 +162,13 @@ public class MCAccessCB2512 implements MCAccess{
}
}
// @Override
// public void correctDirection(final Player player) {
// final EntityPlayer mcPlayer = ((CraftPlayer) player).getHandle();
// // Main direction.
// mcPlayer.yaw = LocUtil.correctYaw(mcPlayer.yaw);
// mcPlayer.pitch = LocUtil.correctPitch(mcPlayer.pitch);
// // Consider setting the lastYaw here too.
// }
}

View File

@ -30,7 +30,12 @@ public class BlockCacheCB2545 extends BlockCache implements IBlockAccess{
@Override
public void setAccess(World world) {
this.world = world == null ? null : ((CraftWorld) world).getHandle();
if (world != null) {
this.maxBlockY = world.getMaxHeight() - 1;
this.world = ((CraftWorld) world).getHandle();
} else {
this.world = null;
}
}
@Override

View File

@ -99,7 +99,7 @@ public class MCAccessCB2545 implements MCAccess{
@Override
public double getJumpAmplifier(final Player player) {
final net.minecraft.server.v1_4_6.EntityPlayer mcPlayer = ((CraftPlayer) player).getHandle();
final EntityPlayer mcPlayer = ((CraftPlayer) player).getHandle();
if (mcPlayer.hasEffect(MobEffectList.JUMP)) return mcPlayer.getEffect(MobEffectList.JUMP).getAmplifier();
else return Double.NEGATIVE_INFINITY;
@ -107,7 +107,7 @@ public class MCAccessCB2545 implements MCAccess{
@Override
public double getFasterMovementAmplifier(final Player player) {
final net.minecraft.server.v1_4_6.EntityPlayer mcPlayer = ((CraftPlayer) player).getHandle();
final EntityPlayer mcPlayer = ((CraftPlayer) player).getHandle();
if (mcPlayer.hasEffect(MobEffectList.FASTER_MOVEMENT)) return mcPlayer.getEffect(MobEffectList.FASTER_MOVEMENT).getAmplifier();
else return Double.NEGATIVE_INFINITY;
}
@ -134,13 +134,13 @@ public class MCAccessCB2545 implements MCAccess{
@Override
public boolean shouldBeZombie(final Player player) {
final net.minecraft.server.v1_4_6.EntityPlayer mcPlayer = ((CraftPlayer) player).getHandle();
final EntityPlayer mcPlayer = ((CraftPlayer) player).getHandle();
return !mcPlayer.dead && mcPlayer.getHealth() <= 0 ;
}
@Override
public void setDead(final Player player, final int deathTicks) {
final net.minecraft.server.v1_4_6.EntityPlayer mcPlayer = ((CraftPlayer) player).getHandle();
final EntityPlayer mcPlayer = ((CraftPlayer) player).getHandle();
mcPlayer.deathTicks = deathTicks;
mcPlayer.dead = true;
}
@ -162,4 +162,13 @@ public class MCAccessCB2545 implements MCAccess{
}
}
// @Override
// public void correctDirection(final Player player) {
// final EntityPlayer mcPlayer = ((CraftPlayer) player).getHandle();
// // Main direction.
// mcPlayer.yaw = LocUtil.correctYaw(mcPlayer.yaw);
// mcPlayer.pitch = LocUtil.correctPitch(mcPlayer.pitch);
// // Consider setting the lastYaw here too.
// }
}

View File

@ -30,7 +30,12 @@ public class BlockCacheCB2602 extends BlockCache implements IBlockAccess{
@Override
public void setAccess(World world) {
this.world = world == null ? null : ((CraftWorld) world).getHandle();
if (world != null) {
this.maxBlockY = world.getMaxHeight() - 1;
this.world = ((CraftWorld) world).getHandle();
} else {
this.world = null;
}
}
@Override

View File

@ -100,7 +100,7 @@ public class MCAccessCB2602 implements MCAccess{
@Override
public double getJumpAmplifier(final Player player) {
final net.minecraft.server.v1_4_R1.EntityPlayer mcPlayer = ((CraftPlayer) player).getHandle();
final EntityPlayer mcPlayer = ((CraftPlayer) player).getHandle();
if (mcPlayer.hasEffect(MobEffectList.JUMP)) return mcPlayer.getEffect(MobEffectList.JUMP).getAmplifier();
else return Double.NEGATIVE_INFINITY;
@ -108,7 +108,7 @@ public class MCAccessCB2602 implements MCAccess{
@Override
public double getFasterMovementAmplifier(final Player player) {
final net.minecraft.server.v1_4_R1.EntityPlayer mcPlayer = ((CraftPlayer) player).getHandle();
final EntityPlayer mcPlayer = ((CraftPlayer) player).getHandle();
if (mcPlayer.hasEffect(MobEffectList.FASTER_MOVEMENT)) return mcPlayer.getEffect(MobEffectList.FASTER_MOVEMENT).getAmplifier();
else return Double.NEGATIVE_INFINITY;
}
@ -135,13 +135,13 @@ public class MCAccessCB2602 implements MCAccess{
@Override
public boolean shouldBeZombie(final Player player) {
final net.minecraft.server.v1_4_R1.EntityPlayer mcPlayer = ((CraftPlayer) player).getHandle();
final EntityPlayer mcPlayer = ((CraftPlayer) player).getHandle();
return !mcPlayer.dead && mcPlayer.getHealth() <= 0 ;
}
@Override
public void setDead(final Player player, final int deathTicks) {
final net.minecraft.server.v1_4_R1.EntityPlayer mcPlayer = ((CraftPlayer) player).getHandle();
final EntityPlayer mcPlayer = ((CraftPlayer) player).getHandle();
mcPlayer.deathTicks = deathTicks;
mcPlayer.dead = true;
}
@ -164,4 +164,13 @@ public class MCAccessCB2602 implements MCAccess{
}
}
// @Override
// public void correctDirection(final Player player) {
// final EntityPlayer mcPlayer = ((CraftPlayer) player).getHandle();
// // Main direction.
// mcPlayer.yaw = LocUtil.correctYaw(mcPlayer.yaw);
// mcPlayer.pitch = LocUtil.correctPitch(mcPlayer.pitch);
// // Consider setting the lastYaw here too.
// }
}

View File

@ -30,7 +30,12 @@ public class BlockCacheCB2645 extends BlockCache implements IBlockAccess{
@Override
public void setAccess(World world) {
this.world = world == null ? null : ((CraftWorld) world).getHandle();
if (world != null) {
this.maxBlockY = world.getMaxHeight() - 1;
this.world = ((CraftWorld) world).getHandle();
} else {
this.world = null;
}
}
@Override

View File

@ -101,7 +101,7 @@ public class MCAccessCB2645 implements MCAccess{
@Override
public double getJumpAmplifier(final Player player) {
final net.minecraft.server.v1_5_R1.EntityPlayer mcPlayer = ((CraftPlayer) player).getHandle();
final EntityPlayer mcPlayer = ((CraftPlayer) player).getHandle();
if (mcPlayer.hasEffect(MobEffectList.JUMP)) return mcPlayer.getEffect(MobEffectList.JUMP).getAmplifier();
else return Double.NEGATIVE_INFINITY;
@ -109,7 +109,7 @@ public class MCAccessCB2645 implements MCAccess{
@Override
public double getFasterMovementAmplifier(final Player player) {
final net.minecraft.server.v1_5_R1.EntityPlayer mcPlayer = ((CraftPlayer) player).getHandle();
final EntityPlayer mcPlayer = ((CraftPlayer) player).getHandle();
if (mcPlayer.hasEffect(MobEffectList.FASTER_MOVEMENT)) return mcPlayer.getEffect(MobEffectList.FASTER_MOVEMENT).getAmplifier();
else return Double.NEGATIVE_INFINITY;
}
@ -136,13 +136,13 @@ public class MCAccessCB2645 implements MCAccess{
@Override
public boolean shouldBeZombie(final Player player) {
final net.minecraft.server.v1_5_R1.EntityPlayer mcPlayer = ((CraftPlayer) player).getHandle();
final EntityPlayer mcPlayer = ((CraftPlayer) player).getHandle();
return !mcPlayer.dead && mcPlayer.getHealth() <= 0 ;
}
@Override
public void setDead(final Player player, final int deathTicks) {
final net.minecraft.server.v1_5_R1.EntityPlayer mcPlayer = ((CraftPlayer) player).getHandle();
final EntityPlayer mcPlayer = ((CraftPlayer) player).getHandle();
mcPlayer.deathTicks = deathTicks;
mcPlayer.dead = true;
}
@ -164,4 +164,13 @@ public class MCAccessCB2645 implements MCAccess{
}
}
// @Override
// public void correctDirection(final Player player) {
// final EntityPlayer mcPlayer = ((CraftPlayer) player).getHandle();
// // Main direction.
// mcPlayer.yaw = LocUtil.correctYaw(mcPlayer.yaw);
// mcPlayer.pitch = LocUtil.correctPitch(mcPlayer.pitch);
// // Consider setting the lastYaw here too.
// }
}

View File

@ -30,7 +30,12 @@ public class BlockCacheCB2691 extends BlockCache implements IBlockAccess{
@Override
public void setAccess(World world) {
this.world = world == null ? null : ((CraftWorld) world).getHandle();
if (world != null) {
this.maxBlockY = world.getMaxHeight() - 1;
this.world = ((CraftWorld) world).getHandle();
} else {
this.world = null;
}
}
@Override

View File

@ -62,7 +62,9 @@ public class MCAccessCB2691 implements MCAccess{
final double entityHeight = Math.max(mcEntity.length, Math.max(mcEntity.height, mcEntity.boundingBox.e - mcEntity.boundingBox.b));
if (entity instanceof LivingEntity) {
return Math.max(((LivingEntity) entity).getEyeHeight(), entityHeight);
} else return entityHeight;
} else {
return entityHeight;
}
}
@Override
@ -101,7 +103,7 @@ public class MCAccessCB2691 implements MCAccess{
@Override
public double getJumpAmplifier(final Player player) {
final net.minecraft.server.v1_5_R2.EntityPlayer mcPlayer = ((CraftPlayer) player).getHandle();
final EntityPlayer mcPlayer = ((CraftPlayer) player).getHandle();
if (mcPlayer.hasEffect(MobEffectList.JUMP)) return mcPlayer.getEffect(MobEffectList.JUMP).getAmplifier();
else return Double.NEGATIVE_INFINITY;
@ -109,7 +111,7 @@ public class MCAccessCB2691 implements MCAccess{
@Override
public double getFasterMovementAmplifier(final Player player) {
final net.minecraft.server.v1_5_R2.EntityPlayer mcPlayer = ((CraftPlayer) player).getHandle();
final EntityPlayer mcPlayer = ((CraftPlayer) player).getHandle();
if (mcPlayer.hasEffect(MobEffectList.FASTER_MOVEMENT)) return mcPlayer.getEffect(MobEffectList.FASTER_MOVEMENT).getAmplifier();
else return Double.NEGATIVE_INFINITY;
}
@ -136,13 +138,13 @@ public class MCAccessCB2691 implements MCAccess{
@Override
public boolean shouldBeZombie(final Player player) {
final net.minecraft.server.v1_5_R2.EntityPlayer mcPlayer = ((CraftPlayer) player).getHandle();
final EntityPlayer mcPlayer = ((CraftPlayer) player).getHandle();
return !mcPlayer.dead && mcPlayer.getHealth() <= 0 ;
}
@Override
public void setDead(final Player player, final int deathTicks) {
final net.minecraft.server.v1_5_R2.EntityPlayer mcPlayer = ((CraftPlayer) player).getHandle();
final EntityPlayer mcPlayer = ((CraftPlayer) player).getHandle();
mcPlayer.deathTicks = deathTicks;
mcPlayer.dead = true;
}
@ -164,4 +166,13 @@ public class MCAccessCB2691 implements MCAccess{
}
}
// @Override
// public void correctDirection(final Player player) {
// final EntityPlayer mcPlayer = ((CraftPlayer) player).getHandle();
// // Main direction.
// mcPlayer.yaw = LocUtil.correctYaw(mcPlayer.yaw);
// mcPlayer.pitch = LocUtil.correctPitch(mcPlayer.pitch);
// // Consider setting the lastYaw here too.
// }
}

View File

@ -30,7 +30,12 @@ public class BlockCacheCB2763 extends BlockCache implements IBlockAccess{
@Override
public void setAccess(World world) {
this.world = world == null ? null : ((CraftWorld) world).getHandle();
if (world != null) {
this.maxBlockY = world.getMaxHeight() - 1;
this.world = ((CraftWorld) world).getHandle();
} else {
this.world = null;
}
}
@Override

View File

@ -101,7 +101,7 @@ public class MCAccessCB2763 implements MCAccess{
@Override
public double getJumpAmplifier(final Player player) {
final net.minecraft.server.v1_5_R3.EntityPlayer mcPlayer = ((CraftPlayer) player).getHandle();
final EntityPlayer mcPlayer = ((CraftPlayer) player).getHandle();
if (mcPlayer.hasEffect(MobEffectList.JUMP)) return mcPlayer.getEffect(MobEffectList.JUMP).getAmplifier();
else return Double.NEGATIVE_INFINITY;
@ -109,7 +109,7 @@ public class MCAccessCB2763 implements MCAccess{
@Override
public double getFasterMovementAmplifier(final Player player) {
final net.minecraft.server.v1_5_R3.EntityPlayer mcPlayer = ((CraftPlayer) player).getHandle();
final EntityPlayer mcPlayer = ((CraftPlayer) player).getHandle();
if (mcPlayer.hasEffect(MobEffectList.FASTER_MOVEMENT)) return mcPlayer.getEffect(MobEffectList.FASTER_MOVEMENT).getAmplifier();
else return Double.NEGATIVE_INFINITY;
}
@ -136,13 +136,13 @@ public class MCAccessCB2763 implements MCAccess{
@Override
public boolean shouldBeZombie(final Player player) {
final net.minecraft.server.v1_5_R3.EntityPlayer mcPlayer = ((CraftPlayer) player).getHandle();
final EntityPlayer mcPlayer = ((CraftPlayer) player).getHandle();
return !mcPlayer.dead && mcPlayer.getHealth() <= 0 ;
}
@Override
public void setDead(final Player player, final int deathTicks) {
final net.minecraft.server.v1_5_R3.EntityPlayer mcPlayer = ((CraftPlayer) player).getHandle();
final EntityPlayer mcPlayer = ((CraftPlayer) player).getHandle();
mcPlayer.deathTicks = deathTicks;
mcPlayer.dead = true;
}
@ -165,4 +165,13 @@ public class MCAccessCB2763 implements MCAccess{
}
}
// @Override
// public void correctDirection(final Player player) {
// final EntityPlayer mcPlayer = ((CraftPlayer) player).getHandle();
// // Main direction.
// mcPlayer.yaw = LocUtil.correctYaw(mcPlayer.yaw);
// mcPlayer.pitch = LocUtil.correctPitch(mcPlayer.pitch);
// // Consider setting the lastYaw here too.
// }
}

View File

@ -24,11 +24,6 @@
<artifactId>craftbukkit</artifactId>
<version>1.6.1-R0.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.bukkit</groupId>
<artifactId>bukkit</artifactId>
<version>1.6.1-R0.1-SNAPSHOT</version>
</dependency>
</dependencies>
<description>Compatibility for CB 2794 (MC 1.6.1).

View File

@ -30,7 +30,12 @@ public class BlockCacheCB2794 extends BlockCache implements IBlockAccess{
@Override
public void setAccess(World world) {
this.world = world == null ? null : ((CraftWorld) world).getHandle();
if (world != null) {
this.maxBlockY = world.getMaxHeight() - 1;
this.world = ((CraftWorld) world).getHandle();
} else {
this.world = null;
}
}
@Override

View File

@ -101,7 +101,7 @@ public class MCAccessCB2794 implements MCAccess{
@Override
public double getJumpAmplifier(final Player player) {
final net.minecraft.server.v1_6_R1.EntityPlayer mcPlayer = ((CraftPlayer) player).getHandle();
final EntityPlayer mcPlayer = ((CraftPlayer) player).getHandle();
if (mcPlayer.hasEffect(MobEffectList.JUMP)) return mcPlayer.getEffect(MobEffectList.JUMP).getAmplifier();
else return Double.NEGATIVE_INFINITY;
@ -109,7 +109,7 @@ public class MCAccessCB2794 implements MCAccess{
@Override
public double getFasterMovementAmplifier(final Player player) {
final net.minecraft.server.v1_6_R1.EntityPlayer mcPlayer = ((CraftPlayer) player).getHandle();
final EntityPlayer mcPlayer = ((CraftPlayer) player).getHandle();
if (mcPlayer.hasEffect(MobEffectList.FASTER_MOVEMENT)) return mcPlayer.getEffect(MobEffectList.FASTER_MOVEMENT).getAmplifier();
else return Double.NEGATIVE_INFINITY;
}
@ -136,13 +136,13 @@ public class MCAccessCB2794 implements MCAccess{
@Override
public boolean shouldBeZombie(final Player player) {
final net.minecraft.server.v1_6_R1.EntityPlayer mcPlayer = ((CraftPlayer) player).getHandle();
final EntityPlayer mcPlayer = ((CraftPlayer) player).getHandle();
return !mcPlayer.dead && mcPlayer.getHealth() <= 0.0f ;
}
@Override
public void setDead(final Player player, final int deathTicks) {
final net.minecraft.server.v1_6_R1.EntityPlayer mcPlayer = ((CraftPlayer) player).getHandle();
final EntityPlayer mcPlayer = ((CraftPlayer) player).getHandle();
mcPlayer.deathTicks = deathTicks;
mcPlayer.dead = true;
}
@ -159,4 +159,13 @@ public class MCAccessCB2794 implements MCAccess{
return mat.hasGravity();
}
// @Override
// public void correctDirection(final Player player) {
// final EntityPlayer mcPlayer = ((CraftPlayer) player).getHandle();
// // Main direction.
// mcPlayer.yaw = LocUtil.correctYaw(mcPlayer.yaw);
// mcPlayer.pitch = LocUtil.correctPitch(mcPlayer.pitch);
// // Consider setting the lastYaw here too.
// }
}

View File

@ -24,11 +24,6 @@
<artifactId>craftbukkit</artifactId>
<version>1.6.2-R1.0</version>
</dependency>
<dependency>
<groupId>org.bukkit</groupId>
<artifactId>bukkit</artifactId>
<version>1.6.2-R1.0</version>
</dependency>
</dependencies>
<description>Compatibility for CB2808 (MC 1.6.2).

View File

@ -30,7 +30,12 @@ public class BlockCacheCB2808 extends BlockCache implements IBlockAccess{
@Override
public void setAccess(World world) {
this.world = world == null ? null : ((CraftWorld) world).getHandle();
if (world != null) {
this.maxBlockY = world.getMaxHeight() - 1;
this.world = ((CraftWorld) world).getHandle();
} else {
this.world = null;
}
}
@Override

View File

@ -102,7 +102,7 @@ public class MCAccessCB2808 implements MCAccess{
@Override
public double getJumpAmplifier(final Player player) {
final net.minecraft.server.v1_6_R2.EntityPlayer mcPlayer = ((CraftPlayer) player).getHandle();
final EntityPlayer mcPlayer = ((CraftPlayer) player).getHandle();
if (mcPlayer.hasEffect(MobEffectList.JUMP)) return mcPlayer.getEffect(MobEffectList.JUMP).getAmplifier();
else return Double.NEGATIVE_INFINITY;
@ -110,7 +110,7 @@ public class MCAccessCB2808 implements MCAccess{
@Override
public double getFasterMovementAmplifier(final Player player) {
final net.minecraft.server.v1_6_R2.EntityPlayer mcPlayer = ((CraftPlayer) player).getHandle();
final EntityPlayer mcPlayer = ((CraftPlayer) player).getHandle();
if (mcPlayer.hasEffect(MobEffectList.FASTER_MOVEMENT)) return mcPlayer.getEffect(MobEffectList.FASTER_MOVEMENT).getAmplifier();
else return Double.NEGATIVE_INFINITY;
}
@ -137,13 +137,13 @@ public class MCAccessCB2808 implements MCAccess{
@Override
public boolean shouldBeZombie(final Player player) {
final net.minecraft.server.v1_6_R2.EntityPlayer mcPlayer = ((CraftPlayer) player).getHandle();
final EntityPlayer mcPlayer = ((CraftPlayer) player).getHandle();
return !mcPlayer.dead && mcPlayer.getHealth() <= 0.0f ;
}
@Override
public void setDead(final Player player, final int deathTicks) {
final net.minecraft.server.v1_6_R2.EntityPlayer mcPlayer = ((CraftPlayer) player).getHandle();
final EntityPlayer mcPlayer = ((CraftPlayer) player).getHandle();
mcPlayer.deathTicks = deathTicks;
mcPlayer.dead = true;
}
@ -160,4 +160,13 @@ public class MCAccessCB2808 implements MCAccess{
return mat.hasGravity();
}
// @Override
// public void correctDirection(final Player player) {
// final EntityPlayer mcPlayer = ((CraftPlayer) player).getHandle();
// // Main direction.
// mcPlayer.yaw = LocUtil.correctYaw(mcPlayer.yaw);
// mcPlayer.pitch = LocUtil.correctPitch(mcPlayer.pitch);
// // Consider setting the lastYaw here too.
// }
}

View File

@ -24,11 +24,6 @@
<artifactId>craftbukkit</artifactId>
<version>1.6.4-R0.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.bukkit</groupId>
<artifactId>bukkit</artifactId>
<version>1.6.4-R0.1-SNAPSHOT</version>
</dependency>
</dependencies>
<description>Compatibility for CB2882 (MC 1.6.4).

View File

@ -30,7 +30,12 @@ public class BlockCacheCB2882 extends BlockCache implements IBlockAccess{
@Override
public void setAccess(World world) {
this.world = world == null ? null : ((CraftWorld) world).getHandle();
if (world != null) {
this.maxBlockY = world.getMaxHeight() - 1;
this.world = ((CraftWorld) world).getHandle();
} else {
this.world = null;
}
}
@Override

View File

@ -103,7 +103,7 @@ public class MCAccessCB2882 implements MCAccess{
@Override
public double getJumpAmplifier(final Player player) {
final net.minecraft.server.v1_6_R3.EntityPlayer mcPlayer = ((CraftPlayer) player).getHandle();
final EntityPlayer mcPlayer = ((CraftPlayer) player).getHandle();
if (mcPlayer.hasEffect(MobEffectList.JUMP)) return mcPlayer.getEffect(MobEffectList.JUMP).getAmplifier();
else return Double.NEGATIVE_INFINITY;
@ -111,7 +111,7 @@ public class MCAccessCB2882 implements MCAccess{
@Override
public double getFasterMovementAmplifier(final Player player) {
final net.minecraft.server.v1_6_R3.EntityPlayer mcPlayer = ((CraftPlayer) player).getHandle();
final EntityPlayer mcPlayer = ((CraftPlayer) player).getHandle();
if (mcPlayer.hasEffect(MobEffectList.FASTER_MOVEMENT)) return mcPlayer.getEffect(MobEffectList.FASTER_MOVEMENT).getAmplifier();
else return Double.NEGATIVE_INFINITY;
}
@ -138,13 +138,13 @@ public class MCAccessCB2882 implements MCAccess{
@Override
public boolean shouldBeZombie(final Player player) {
final net.minecraft.server.v1_6_R3.EntityPlayer mcPlayer = ((CraftPlayer) player).getHandle();
final EntityPlayer mcPlayer = ((CraftPlayer) player).getHandle();
return !mcPlayer.dead && mcPlayer.getHealth() <= 0.0f ;
}
@Override
public void setDead(final Player player, final int deathTicks) {
final net.minecraft.server.v1_6_R3.EntityPlayer mcPlayer = ((CraftPlayer) player).getHandle();
final EntityPlayer mcPlayer = ((CraftPlayer) player).getHandle();
mcPlayer.deathTicks = deathTicks;
mcPlayer.dead = true;
}
@ -161,4 +161,13 @@ public class MCAccessCB2882 implements MCAccess{
return mat.hasGravity();
}
// @Override
// public void correctDirection(final Player player) {
// final EntityPlayer mcPlayer = ((CraftPlayer) player).getHandle();
// // Main direction.
// mcPlayer.yaw = LocUtil.correctYaw(mcPlayer.yaw);
// mcPlayer.pitch = LocUtil.correctPitch(mcPlayer.pitch);
// // Consider setting the lastYaw here too.
// }
}

View File

@ -2,9 +2,9 @@
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>fr.neatmonster</groupId>
<artifactId>ncpcompatcb2511</artifactId>
<artifactId>ncpcompatcb2922</artifactId>
<packaging>jar</packaging>
<name>NCPCompatCB2511</name>
<name>NCPCompatCB2922</name>
<version>static</version>
<parent>
@ -22,11 +22,11 @@
<dependency>
<groupId>org.bukkit</groupId>
<artifactId>craftbukkit</artifactId>
<version>1.4.5-R0.2</version>
<version>1.7.2-R0.4-SNAPSHOT</version>
</dependency>
</dependencies>
<description>Compatibility up to CB2512 (i.e. 1.4.5-R0.2).
<description>Compatibility for CB2922 (MC 1.7.2).
Version updating is done for the NoCheatPlus sub-module.</description>
</project>

View File

@ -0,0 +1,127 @@
package fr.neatmonster.nocheatplus.compat.cb2922;
import java.util.Iterator;
import java.util.List;
import net.minecraft.server.v1_7_R1.AxisAlignedBB;
import net.minecraft.server.v1_7_R1.Block;
import net.minecraft.server.v1_7_R1.EntityBoat;
import net.minecraft.server.v1_7_R1.IBlockAccess;
import net.minecraft.server.v1_7_R1.TileEntity;
import net.minecraft.server.v1_7_R1.Vec3DPool;
import org.bukkit.World;
import org.bukkit.craftbukkit.v1_7_R1.CraftWorld;
import org.bukkit.craftbukkit.v1_7_R1.entity.CraftEntity;
import org.bukkit.entity.Entity;
import fr.neatmonster.nocheatplus.utilities.BlockCache;
public class BlockCacheCB2922 extends BlockCache implements IBlockAccess{
/** Box for one time use, no nesting, no extra storing this(!). */
protected static final AxisAlignedBB useBox = AxisAlignedBB.a(0, 0, 0, 0, 0, 0);
protected net.minecraft.server.v1_7_R1.WorldServer world;
public BlockCacheCB2922(World world) {
setAccess(world);
}
@Override
public void setAccess(World world) {
if (world != null) {
this.maxBlockY = world.getMaxHeight() - 1;
this.world = ((CraftWorld) world).getHandle();
} else {
this.world = null;
}
}
@Override
public int fetchTypeId(final int x, final int y, final int z) {
return world.getTypeId(x, y, z);
}
@Override
public int fetchData(final int x, final int y, final int z) {
return world.getData(x, y, z);
}
@Override
public double[] fetchBounds(final int x, final int y, final int z){
// TODO: change api for this / use nodes (!)
final int id = getTypeId(x, y, z);
final net.minecraft.server.v1_7_R1.Block block = net.minecraft.server.v1_7_R1.Block.e(id);
if (block == null) return null;
block.updateShape(this, x, y, z); // TODO: use THIS instead of world.
// minX, minY, minZ, maxX, maxY, maxZ
return new double[]{block.x(), block.z(), block.B(), block.y(), block.A(), block.C()};
}
@Override
public boolean standsOnEntity(final Entity entity, final double minX, final double minY, final double minZ, final double maxX, final double maxY, final double maxZ){
try{
// TODO: Probably check other ids too before doing this ?
final net.minecraft.server.v1_7_R1.Entity mcEntity = ((CraftEntity) entity).getHandle();
final AxisAlignedBB box = useBox.b(minX, minY, minZ, maxX, maxY, maxZ);
@SuppressWarnings("rawtypes")
final List list = world.getEntities(mcEntity, box);
@SuppressWarnings("rawtypes")
final Iterator iterator = list.iterator();
while (iterator.hasNext()) {
final net.minecraft.server.v1_7_R1.Entity other = (net.minecraft.server.v1_7_R1.Entity) iterator.next();
if (!(other instanceof EntityBoat)){ // && !(other instanceof EntityMinecart)) continue;
continue;
}
if (minY >= other.locY && minY - other.locY <= 0.7){
return true;
}
// Still check this for some reason.
final AxisAlignedBB otherBox = other.boundingBox;
if (box.a > otherBox.d || box.d < otherBox.a || box.b > otherBox.e || box.e < otherBox.b || box.c > otherBox.f || box.f < otherBox.c) continue;
else {
return true;
}
}
}
catch (Throwable t){
// Ignore exceptions (Context: DisguiseCraft).
}
return false;
}
/* (non-Javadoc)
* @see fr.neatmonster.nocheatplus.utilities.BlockCache#cleanup()
*/
@Override
public void cleanup() {
super.cleanup();
world = null;
}
@Override
public TileEntity getTileEntity(final int x, final int y, final int z) {
return world.getTileEntity(x, y, z);
}
@Override
public int getBlockPower(final int arg0, final int arg1, final int arg2, final int arg3) {
return world.getBlockPower(arg0, arg1, arg2, arg3);
}
@Override
public Block getType(int x, int y, int z) {
return world.getType(x, y, z);
}
@Override
public Vec3DPool getVec3DPool() {
return world.getVec3DPool();
}
}

View File

@ -1,19 +1,19 @@
package fr.neatmonster.nocheatplus.compat.cb2511;
package fr.neatmonster.nocheatplus.compat.cb2922;
import net.minecraft.server.AxisAlignedBB;
import net.minecraft.server.Block;
import net.minecraft.server.DamageSource;
import net.minecraft.server.EntityComplexPart;
import net.minecraft.server.EntityPlayer;
import net.minecraft.server.MobEffectList;
import net.minecraft.server.v1_7_R1.AxisAlignedBB;
import net.minecraft.server.v1_7_R1.Block;
import net.minecraft.server.v1_7_R1.DamageSource;
import net.minecraft.server.v1_7_R1.EntityComplexPart;
import net.minecraft.server.v1_7_R1.EntityPlayer;
import net.minecraft.server.v1_7_R1.MobEffectList;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.command.CommandMap;
import org.bukkit.craftbukkit.CraftServer;
import org.bukkit.craftbukkit.entity.CraftEntity;
import org.bukkit.craftbukkit.entity.CraftPlayer;
import org.bukkit.craftbukkit.v1_7_R1.CraftServer;
import org.bukkit.craftbukkit.v1_7_R1.entity.CraftEntity;
import org.bukkit.craftbukkit.v1_7_R1.entity.CraftPlayer;
import org.bukkit.entity.Entity;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player;
@ -23,33 +23,29 @@ import fr.neatmonster.nocheatplus.compat.MCAccess;
import fr.neatmonster.nocheatplus.utilities.BlockCache;
import fr.neatmonster.nocheatplus.utilities.ReflectionUtil;
public class MCAccessCB2511 implements MCAccess {
public class MCAccessCB2922 implements MCAccess{
/**
* Constructor to let it fail in time.
* Constructor to let it fail.
*/
public MCAccessCB2511(){
public MCAccessCB2922(){
getCommandMap();
ReflectionUtil.checkMembers("net.minecraft.server.", new String[]{"Entity" , "dead"});
ReflectionUtil.checkMembers("net.minecraft.server.", new String[]{"EntityPlayer" , "netServerHandler"});
ReflectionUtil.checkMethodReturnTypesNoArgs(net.minecraft.server.Block.class,
new String[]{"v", "w", "x", "y", "z", "A"}, double.class);
ReflectionUtil.checkMembers("net.minecraft.server.v1_7_R1.", new String[]{"Entity" , "dead"});
// block bounds, original: minX, maxX, minY, maxY, minZ, maxZ
ReflectionUtil.checkMethodReturnTypesNoArgs(net.minecraft.server.v1_7_R1.Block.class,
new String[]{"x", "y", "z", "A", "B", "C"}, double.class);
// TODO: Nail it down further.
}
@Override
public String getMCVersion() {
return "1.4.2|1.4.4|1.4.5";
// 1_7_R1
return "1.7.2";
}
@Override
public String getServerVersionTag() {
return "CB2511";
}
@Override
public BlockCache getBlockCache(World world) {
return new BlockCacheCB2511(world);
return "CB2922";
}
@Override
@ -57,9 +53,14 @@ public class MCAccessCB2511 implements MCAccess {
return ((CraftServer) Bukkit.getServer()).getCommandMap();
}
@Override
public BlockCache getBlockCache(final World world) {
return new BlockCacheCB2922(world);
}
@Override
public double getHeight(final Entity entity) {
final net.minecraft.server.Entity mcEntity = ((CraftEntity) entity).getHandle();
final net.minecraft.server.v1_7_R1.Entity mcEntity = ((CraftEntity) entity).getHandle();
final double entityHeight = Math.max(mcEntity.length, Math.max(mcEntity.height, mcEntity.boundingBox.e - mcEntity.boundingBox.b));
if (entity instanceof LivingEntity) {
return Math.max(((LivingEntity) entity).getEyeHeight(), entityHeight);
@ -68,16 +69,16 @@ public class MCAccessCB2511 implements MCAccess {
@Override
public AlmostBoolean isBlockSolid(final int id) {
final Block block = Block.byId[id];
if (block == null || block.material == null) return AlmostBoolean.MAYBE;
else return AlmostBoolean.match(block.material.isSolid());
final Block block = Block.e(id);
if (block == null || block.getMaterial() == null) return AlmostBoolean.MAYBE;
else return AlmostBoolean.match(block.getMaterial().isSolid());
}
@Override
public AlmostBoolean isBlockLiquid(final int id) {
final Block block = Block.byId[id];
if (block == null || block.material == null) return AlmostBoolean.MAYBE;
else return AlmostBoolean.match(block.material.isLiquid());
final Block block = Block.e(id);
if (block == null || block.getMaterial() == null) return AlmostBoolean.MAYBE;
else return AlmostBoolean.match(block.getMaterial().isLiquid());
}
@Override
@ -89,6 +90,7 @@ public class MCAccessCB2511 implements MCAccess {
public AlmostBoolean isIllegalBounds(final Player player) {
final EntityPlayer entityPlayer = ((CraftPlayer) player).getHandle();
if (entityPlayer.dead) return AlmostBoolean.NO;
// TODO: Does this need a method call for the "real" box? Might be no problem during moving events, though.
final AxisAlignedBB box = entityPlayer.boundingBox;
if (!entityPlayer.isSleeping()){
// This can not really test stance but height of bounding box.
@ -101,7 +103,7 @@ public class MCAccessCB2511 implements MCAccess {
@Override
public double getJumpAmplifier(final Player player) {
final net.minecraft.server.EntityPlayer mcPlayer = ((CraftPlayer) player).getHandle();
final EntityPlayer mcPlayer = ((CraftPlayer) player).getHandle();
if (mcPlayer.hasEffect(MobEffectList.JUMP)) return mcPlayer.getEffect(MobEffectList.JUMP).getAmplifier();
else return Double.NEGATIVE_INFINITY;
@ -109,7 +111,7 @@ public class MCAccessCB2511 implements MCAccess {
@Override
public double getFasterMovementAmplifier(final Player player) {
final net.minecraft.server.EntityPlayer mcPlayer = ((CraftPlayer) player).getHandle();
final EntityPlayer mcPlayer = ((CraftPlayer) player).getHandle();
if (mcPlayer.hasEffect(MobEffectList.FASTER_MOVEMENT)) return mcPlayer.getEffect(MobEffectList.FASTER_MOVEMENT).getAmplifier();
else return Double.NEGATIVE_INFINITY;
}
@ -126,7 +128,7 @@ public class MCAccessCB2511 implements MCAccess {
@Override
public void dealFallDamage(final Player player, final double damage) {
((CraftPlayer) player).getHandle().damageEntity(DamageSource.FALL, (int) Math.round(damage));
((CraftPlayer) player).getHandle().damageEntity(DamageSource.FALL, (float) damage);
}
@Override
@ -136,13 +138,13 @@ public class MCAccessCB2511 implements MCAccess {
@Override
public boolean shouldBeZombie(final Player player) {
final net.minecraft.server.EntityPlayer mcPlayer = ((CraftPlayer) player).getHandle();
return !mcPlayer.dead && mcPlayer.getHealth() <= 0 ;
final EntityPlayer mcPlayer = ((CraftPlayer) player).getHandle();
return !mcPlayer.dead && mcPlayer.getHealth() <= 0.0f ;
}
@Override
public void setDead(final Player player, final int deathTicks) {
final net.minecraft.server.EntityPlayer mcPlayer = ((CraftPlayer) player).getHandle();
final EntityPlayer mcPlayer = ((CraftPlayer) player).getHandle();
mcPlayer.deathTicks = deathTicks;
mcPlayer.dead = true;
}
@ -155,13 +157,17 @@ public class MCAccessCB2511 implements MCAccess {
@Override
public boolean hasGravity(final Material mat) {
switch(mat){
case SAND:
case GRAVEL:
return true;
default:
return false;
}
// TODO: Test/check.
return mat.hasGravity();
}
// @Override
// public void correctDirection(final Player player) {
// final EntityPlayer mcPlayer = ((CraftPlayer) player).getHandle();
// // Main direction.
// mcPlayer.yaw = LocUtil.correctYaw(mcPlayer.yaw);
// mcPlayer.pitch = LocUtil.correctPitch(mcPlayer.pitch);
// // Consider setting the lastYaw here too.
// }
}

32
NCPCompatCB3026/pom.xml Normal file
View File

@ -0,0 +1,32 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>fr.neatmonster</groupId>
<artifactId>ncpcompatcb3026</artifactId>
<packaging>jar</packaging>
<name>NCPCompatCB3026</name>
<version>static</version>
<parent>
<groupId>fr.neatmonster</groupId>
<artifactId>nocheatplus-parent</artifactId>
<version>static</version>
</parent>
<dependencies>
<dependency>
<groupId>fr.neatmonster</groupId>
<artifactId>ncpcore</artifactId>
<version>static</version>
</dependency>
<dependency>
<groupId>org.bukkit</groupId>
<artifactId>craftbukkit</artifactId>
<version>1.7.5-R0.1-SNAPSHOT</version>
</dependency>
</dependencies>
<description>Compatibility for CB3026 (MC 1.7.5).
Version updating is done for the NoCheatPlus sub-module.</description>
</project>

View File

@ -0,0 +1,121 @@
package fr.neatmonster.nocheatplus.compat.cb3026;
import java.util.Iterator;
import java.util.List;
import net.minecraft.server.v1_7_R2.AxisAlignedBB;
import net.minecraft.server.v1_7_R2.Block;
import net.minecraft.server.v1_7_R2.EntityBoat;
import net.minecraft.server.v1_7_R2.IBlockAccess;
import net.minecraft.server.v1_7_R2.TileEntity;
import org.bukkit.World;
import org.bukkit.craftbukkit.v1_7_R2.CraftWorld;
import org.bukkit.craftbukkit.v1_7_R2.entity.CraftEntity;
import org.bukkit.entity.Entity;
import fr.neatmonster.nocheatplus.utilities.BlockCache;
public class BlockCacheCB3026 extends BlockCache implements IBlockAccess{
/** Box for one time use, no nesting, no extra storing this(!). */
protected static final AxisAlignedBB useBox = AxisAlignedBB.a(0, 0, 0, 0, 0, 0);
protected net.minecraft.server.v1_7_R2.WorldServer world;
public BlockCacheCB3026(World world) {
setAccess(world);
}
@Override
public void setAccess(World world) {
if (world != null) {
this.maxBlockY = world.getMaxHeight() - 1;
this.world = ((CraftWorld) world).getHandle();
} else {
this.world = null;
}
}
@Override
public int fetchTypeId(final int x, final int y, final int z) {
return world.getTypeId(x, y, z);
}
@Override
public int fetchData(final int x, final int y, final int z) {
return world.getData(x, y, z);
}
@Override
public double[] fetchBounds(final int x, final int y, final int z){
// TODO: change api for this / use nodes (!)
final int id = getTypeId(x, y, z);
final net.minecraft.server.v1_7_R2.Block block = net.minecraft.server.v1_7_R2.Block.e(id);
if (block == null) return null;
block.updateShape(this, x, y, z); // TODO: use THIS instead of world.
// minX, minY, minZ, maxX, maxY, maxZ
return new double[]{block.x(), block.z(), block.B(), block.y(), block.A(), block.C()};
}
@Override
public boolean standsOnEntity(final Entity entity, final double minX, final double minY, final double minZ, final double maxX, final double maxY, final double maxZ){
try{
// TODO: Probably check other ids too before doing this ?
final net.minecraft.server.v1_7_R2.Entity mcEntity = ((CraftEntity) entity).getHandle();
final AxisAlignedBB box = useBox.b(minX, minY, minZ, maxX, maxY, maxZ);
@SuppressWarnings("rawtypes")
final List list = world.getEntities(mcEntity, box);
@SuppressWarnings("rawtypes")
final Iterator iterator = list.iterator();
while (iterator.hasNext()) {
final net.minecraft.server.v1_7_R2.Entity other = (net.minecraft.server.v1_7_R2.Entity) iterator.next();
if (!(other instanceof EntityBoat)){ // && !(other instanceof EntityMinecart)) continue;
continue;
}
if (minY >= other.locY && minY - other.locY <= 0.7){
return true;
}
// Still check this for some reason.
final AxisAlignedBB otherBox = other.boundingBox;
if (box.a > otherBox.d || box.d < otherBox.a || box.b > otherBox.e || box.e < otherBox.b || box.c > otherBox.f || box.f < otherBox.c) continue;
else {
return true;
}
}
}
catch (Throwable t){
// Ignore exceptions (Context: DisguiseCraft).
}
return false;
}
/* (non-Javadoc)
* @see fr.neatmonster.nocheatplus.utilities.BlockCache#cleanup()
*/
@Override
public void cleanup() {
super.cleanup();
world = null;
}
@Override
public TileEntity getTileEntity(final int x, final int y, final int z) {
return world.getTileEntity(x, y, z);
}
@Override
public int getBlockPower(final int arg0, final int arg1, final int arg2, final int arg3) {
return world.getBlockPower(arg0, arg1, arg2, arg3);
}
@Override
public Block getType(int x, int y, int z) {
return world.getType(x, y, z);
}
}

View File

@ -0,0 +1,173 @@
package fr.neatmonster.nocheatplus.compat.cb3026;
import net.minecraft.server.v1_7_R2.AxisAlignedBB;
import net.minecraft.server.v1_7_R2.Block;
import net.minecraft.server.v1_7_R2.DamageSource;
import net.minecraft.server.v1_7_R2.EntityComplexPart;
import net.minecraft.server.v1_7_R2.EntityPlayer;
import net.minecraft.server.v1_7_R2.MobEffectList;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.command.CommandMap;
import org.bukkit.craftbukkit.v1_7_R2.CraftServer;
import org.bukkit.craftbukkit.v1_7_R2.entity.CraftEntity;
import org.bukkit.craftbukkit.v1_7_R2.entity.CraftPlayer;
import org.bukkit.entity.Entity;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player;
import fr.neatmonster.nocheatplus.compat.AlmostBoolean;
import fr.neatmonster.nocheatplus.compat.MCAccess;
import fr.neatmonster.nocheatplus.utilities.BlockCache;
import fr.neatmonster.nocheatplus.utilities.ReflectionUtil;
public class MCAccessCB3026 implements MCAccess{
/**
* Constructor to let it fail.
*/
public MCAccessCB3026(){
getCommandMap();
ReflectionUtil.checkMembers("net.minecraft.server.v1_7_R2.", new String[]{"Entity" , "dead"});
// block bounds, original: minX, maxX, minY, maxY, minZ, maxZ
ReflectionUtil.checkMethodReturnTypesNoArgs(net.minecraft.server.v1_7_R2.Block.class,
new String[]{"x", "y", "z", "A", "B", "C"}, double.class);
// TODO: Nail it down further.
}
@Override
public String getMCVersion() {
// 1_7_R2
return "1.7.5";
}
@Override
public String getServerVersionTag() {
return "CB3026";
}
@Override
public CommandMap getCommandMap() {
return ((CraftServer) Bukkit.getServer()).getCommandMap();
}
@Override
public BlockCache getBlockCache(final World world) {
return new BlockCacheCB3026(world);
}
@Override
public double getHeight(final Entity entity) {
final net.minecraft.server.v1_7_R2.Entity mcEntity = ((CraftEntity) entity).getHandle();
final double entityHeight = Math.max(mcEntity.length, Math.max(mcEntity.height, mcEntity.boundingBox.e - mcEntity.boundingBox.b));
if (entity instanceof LivingEntity) {
return Math.max(((LivingEntity) entity).getEyeHeight(), entityHeight);
} else return entityHeight;
}
@Override
public AlmostBoolean isBlockSolid(final int id) {
final Block block = Block.e(id);
if (block == null || block.getMaterial() == null) return AlmostBoolean.MAYBE;
else return AlmostBoolean.match(block.getMaterial().isSolid());
}
@Override
public AlmostBoolean isBlockLiquid(final int id) {
final Block block = Block.e(id);
if (block == null || block.getMaterial() == null) return AlmostBoolean.MAYBE;
else return AlmostBoolean.match(block.getMaterial().isLiquid());
}
@Override
public double getWidth(final Entity entity) {
return ((CraftEntity) entity).getHandle().width;
}
@Override
public AlmostBoolean isIllegalBounds(final Player player) {
final EntityPlayer entityPlayer = ((CraftPlayer) player).getHandle();
if (entityPlayer.dead) return AlmostBoolean.NO;
// TODO: Does this need a method call for the "real" box? Might be no problem during moving events, though.
final AxisAlignedBB box = entityPlayer.boundingBox;
if (!entityPlayer.isSleeping()){
// This can not really test stance but height of bounding box.
final double dY = Math.abs(box.e - box.b);
if (dY > 1.8) return AlmostBoolean.YES; // dY > 1.65D ||
if (dY < 0.1D && entityPlayer.length >= 0.1) return AlmostBoolean.YES;
}
return AlmostBoolean.MAYBE;
}
@Override
public double getJumpAmplifier(final Player player) {
final EntityPlayer mcPlayer = ((CraftPlayer) player).getHandle();
if (mcPlayer.hasEffect(MobEffectList.JUMP)) return mcPlayer.getEffect(MobEffectList.JUMP).getAmplifier();
else return Double.NEGATIVE_INFINITY;
}
@Override
public double getFasterMovementAmplifier(final Player player) {
final EntityPlayer mcPlayer = ((CraftPlayer) player).getHandle();
if (mcPlayer.hasEffect(MobEffectList.FASTER_MOVEMENT)) return mcPlayer.getEffect(MobEffectList.FASTER_MOVEMENT).getAmplifier();
else return Double.NEGATIVE_INFINITY;
}
@Override
public int getInvulnerableTicks(final Player player) {
return ((CraftPlayer) player).getHandle().invulnerableTicks;
}
@Override
public void setInvulnerableTicks(final Player player, final int ticks) {
((CraftPlayer) player).getHandle().invulnerableTicks = ticks;
}
@Override
public void dealFallDamage(final Player player, final double damage) {
((CraftPlayer) player).getHandle().damageEntity(DamageSource.FALL, (float) damage);
}
@Override
public boolean isComplexPart(final Entity entity) {
return ((CraftEntity) entity).getHandle() instanceof EntityComplexPart;
}
@Override
public boolean shouldBeZombie(final Player player) {
final EntityPlayer mcPlayer = ((CraftPlayer) player).getHandle();
return !mcPlayer.dead && mcPlayer.getHealth() <= 0.0f ;
}
@Override
public void setDead(final Player player, final int deathTicks) {
final EntityPlayer mcPlayer = ((CraftPlayer) player).getHandle();
mcPlayer.deathTicks = deathTicks;
mcPlayer.dead = true;
}
@Override
public long getKeepAliveTime(final Player player) {
// TODO: Implement if possible.
return Long.MIN_VALUE;
}
@Override
public boolean hasGravity(final Material mat) {
// TODO: Test/check.
return mat.hasGravity();
}
// @Override
// public void correctDirection(final Player player) {
// final EntityPlayer mcPlayer = ((CraftPlayer) player).getHandle();
// // Main direction.
// mcPlayer.yaw = LocUtil.correctYaw(mcPlayer.yaw);
// mcPlayer.pitch = LocUtil.correctPitch(mcPlayer.pitch);
// // Consider setting the lastYaw here too.
// }
}

32
NCPCompatCB3043/pom.xml Normal file
View File

@ -0,0 +1,32 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>fr.neatmonster</groupId>
<artifactId>ncpcompatcb3043</artifactId>
<packaging>jar</packaging>
<name>NCPCompatCB3043</name>
<version>static</version>
<parent>
<groupId>fr.neatmonster</groupId>
<artifactId>nocheatplus-parent</artifactId>
<version>static</version>
</parent>
<dependencies>
<dependency>
<groupId>fr.neatmonster</groupId>
<artifactId>ncpcore</artifactId>
<version>static</version>
</dependency>
<dependency>
<groupId>org.bukkit</groupId>
<artifactId>craftbukkit</artifactId>
<version>1.7.9-R0.2-SNAPSHOT</version>
</dependency>
</dependencies>
<description>Compatibility for CB3043 (MC 1.7.10).
Version updating is done for the NoCheatPlus sub-module.</description>
</project>

View File

@ -0,0 +1,121 @@
package fr.neatmonster.nocheatplus.compat.cb3043;
import java.util.Iterator;
import java.util.List;
import net.minecraft.server.v1_7_R3.AxisAlignedBB;
import net.minecraft.server.v1_7_R3.Block;
import net.minecraft.server.v1_7_R3.EntityBoat;
import net.minecraft.server.v1_7_R3.IBlockAccess;
import net.minecraft.server.v1_7_R3.TileEntity;
import org.bukkit.World;
import org.bukkit.craftbukkit.v1_7_R3.CraftWorld;
import org.bukkit.craftbukkit.v1_7_R3.entity.CraftEntity;
import org.bukkit.entity.Entity;
import fr.neatmonster.nocheatplus.utilities.BlockCache;
public class BlockCacheCB3043 extends BlockCache implements IBlockAccess{
/** Box for one time use, no nesting, no extra storing this(!). */
protected static final AxisAlignedBB useBox = AxisAlignedBB.a(0, 0, 0, 0, 0, 0);
protected net.minecraft.server.v1_7_R3.WorldServer world;
public BlockCacheCB3043(World world) {
setAccess(world);
}
@Override
public void setAccess(World world) {
if (world != null) {
this.maxBlockY = world.getMaxHeight() - 1;
this.world = ((CraftWorld) world).getHandle();
} else {
this.world = null;
}
}
@Override
public int fetchTypeId(final int x, final int y, final int z) {
return world.getTypeId(x, y, z);
}
@Override
public int fetchData(final int x, final int y, final int z) {
return world.getData(x, y, z);
}
@Override
public double[] fetchBounds(final int x, final int y, final int z){
// TODO: change api for this / use nodes (!)
final int id = getTypeId(x, y, z);
final net.minecraft.server.v1_7_R3.Block block = net.minecraft.server.v1_7_R3.Block.e(id);
if (block == null) return null;
block.updateShape(this, x, y, z); // TODO: use THIS instead of world.
// minX, minY, minZ, maxX, maxY, maxZ
return new double[]{block.x(), block.z(), block.B(), block.y(), block.A(), block.C()};
}
@Override
public boolean standsOnEntity(final Entity entity, final double minX, final double minY, final double minZ, final double maxX, final double maxY, final double maxZ){
try{
// TODO: Probably check other ids too before doing this ?
final net.minecraft.server.v1_7_R3.Entity mcEntity = ((CraftEntity) entity).getHandle();
final AxisAlignedBB box = useBox.b(minX, minY, minZ, maxX, maxY, maxZ);
@SuppressWarnings("rawtypes")
final List list = world.getEntities(mcEntity, box);
@SuppressWarnings("rawtypes")
final Iterator iterator = list.iterator();
while (iterator.hasNext()) {
final net.minecraft.server.v1_7_R3.Entity other = (net.minecraft.server.v1_7_R3.Entity) iterator.next();
if (!(other instanceof EntityBoat)){ // && !(other instanceof EntityMinecart)) continue;
continue;
}
if (minY >= other.locY && minY - other.locY <= 0.7){
return true;
}
// Still check this for some reason.
final AxisAlignedBB otherBox = other.boundingBox;
if (box.a > otherBox.d || box.d < otherBox.a || box.b > otherBox.e || box.e < otherBox.b || box.c > otherBox.f || box.f < otherBox.c) continue;
else {
return true;
}
}
}
catch (Throwable t){
// Ignore exceptions (Context: DisguiseCraft).
}
return false;
}
/* (non-Javadoc)
* @see fr.neatmonster.nocheatplus.utilities.BlockCache#cleanup()
*/
@Override
public void cleanup() {
super.cleanup();
world = null;
}
@Override
public TileEntity getTileEntity(final int x, final int y, final int z) {
return world.getTileEntity(x, y, z);
}
@Override
public int getBlockPower(final int arg0, final int arg1, final int arg2, final int arg3) {
return world.getBlockPower(arg0, arg1, arg2, arg3);
}
@Override
public Block getType(int x, int y, int z) {
return world.getType(x, y, z);
}
}

View File

@ -0,0 +1,192 @@
package fr.neatmonster.nocheatplus.compat.cb3043;
import net.minecraft.server.v1_7_R3.AxisAlignedBB;
import net.minecraft.server.v1_7_R3.Block;
import net.minecraft.server.v1_7_R3.DamageSource;
import net.minecraft.server.v1_7_R3.EntityComplexPart;
import net.minecraft.server.v1_7_R3.EntityPlayer;
import net.minecraft.server.v1_7_R3.MobEffectList;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.command.CommandMap;
import org.bukkit.craftbukkit.v1_7_R3.CraftServer;
import org.bukkit.craftbukkit.v1_7_R3.entity.CraftEntity;
import org.bukkit.craftbukkit.v1_7_R3.entity.CraftPlayer;
import org.bukkit.entity.Entity;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player;
import fr.neatmonster.nocheatplus.compat.AlmostBoolean;
import fr.neatmonster.nocheatplus.compat.MCAccess;
import fr.neatmonster.nocheatplus.utilities.BlockCache;
import fr.neatmonster.nocheatplus.utilities.ReflectionUtil;
public class MCAccessCB3043 implements MCAccess{
/**
* Constructor to let it fail.
*/
public MCAccessCB3043() {
getCommandMap();
ReflectionUtil.checkMembers("net.minecraft.server.v1_7_R3.", new String[] {"Entity" , "dead"});
// block bounds, original: minX, maxX, minY, maxY, minZ, maxZ
ReflectionUtil.checkMethodReturnTypesNoArgs(net.minecraft.server.v1_7_R3.Block.class,
new String[]{"x", "y", "z", "A", "B", "C"}, double.class);
// TODO: Nail it down further.
}
@Override
public String getMCVersion() {
// 1_7_R3
return "1.7.8|1.7.9";
}
@Override
public String getServerVersionTag() {
return "CB3043";
}
@Override
public CommandMap getCommandMap() {
return ((CraftServer) Bukkit.getServer()).getCommandMap();
}
@Override
public BlockCache getBlockCache(final World world) {
return new BlockCacheCB3043(world);
}
@Override
public double getHeight(final Entity entity) {
final net.minecraft.server.v1_7_R3.Entity mcEntity = ((CraftEntity) entity).getHandle();
final double entityHeight = Math.max(mcEntity.length, Math.max(mcEntity.height, mcEntity.boundingBox.e - mcEntity.boundingBox.b));
if (entity instanceof LivingEntity) {
return Math.max(((LivingEntity) entity).getEyeHeight(), entityHeight);
} else return entityHeight;
}
@Override
public AlmostBoolean isBlockSolid(final int id) {
final Block block = Block.e(id);
if (block == null || block.getMaterial() == null) {
return AlmostBoolean.MAYBE;
}
else {
return AlmostBoolean.match(block.getMaterial().isSolid());
}
}
@Override
public AlmostBoolean isBlockLiquid(final int id) {
final Block block = Block.e(id);
if (block == null || block.getMaterial() == null) {
return AlmostBoolean.MAYBE;
}
else {
return AlmostBoolean.match(block.getMaterial().isLiquid());
}
}
@Override
public double getWidth(final Entity entity) {
return ((CraftEntity) entity).getHandle().width;
}
@Override
public AlmostBoolean isIllegalBounds(final Player player) {
final EntityPlayer entityPlayer = ((CraftPlayer) player).getHandle();
if (entityPlayer.dead) return AlmostBoolean.NO;
// TODO: Does this need a method call for the "real" box? Might be no problem during moving events, though.
final AxisAlignedBB box = entityPlayer.boundingBox;
if (!entityPlayer.isSleeping()) {
// This can not really test stance but height of bounding box.
final double dY = Math.abs(box.e - box.b);
if (dY > 1.8) {
return AlmostBoolean.YES; // dY > 1.65D ||
}
if (dY < 0.1D && entityPlayer.length >= 0.1) {
return AlmostBoolean.YES;
}
}
return AlmostBoolean.MAYBE;
}
@Override
public double getJumpAmplifier(final Player player) {
final EntityPlayer mcPlayer = ((CraftPlayer) player).getHandle();
if (mcPlayer.hasEffect(MobEffectList.JUMP)) {
return mcPlayer.getEffect(MobEffectList.JUMP).getAmplifier();
}
else {
return Double.NEGATIVE_INFINITY;
}
}
@Override
public double getFasterMovementAmplifier(final Player player) {
final EntityPlayer mcPlayer = ((CraftPlayer) player).getHandle();
if (mcPlayer.hasEffect(MobEffectList.FASTER_MOVEMENT)) {
return mcPlayer.getEffect(MobEffectList.FASTER_MOVEMENT).getAmplifier();
}
else {
return Double.NEGATIVE_INFINITY;
}
}
@Override
public int getInvulnerableTicks(final Player player) {
return ((CraftPlayer) player).getHandle().invulnerableTicks;
}
@Override
public void setInvulnerableTicks(final Player player, final int ticks) {
((CraftPlayer) player).getHandle().invulnerableTicks = ticks;
}
@Override
public void dealFallDamage(final Player player, final double damage) {
((CraftPlayer) player).getHandle().damageEntity(DamageSource.FALL, (float) damage);
}
@Override
public boolean isComplexPart(final Entity entity) {
return ((CraftEntity) entity).getHandle() instanceof EntityComplexPart;
}
@Override
public boolean shouldBeZombie(final Player player) {
final EntityPlayer mcPlayer = ((CraftPlayer) player).getHandle();
return !mcPlayer.dead && mcPlayer.getHealth() <= 0.0f ;
}
@Override
public void setDead(final Player player, final int deathTicks) {
final EntityPlayer mcPlayer = ((CraftPlayer) player).getHandle();
mcPlayer.deathTicks = deathTicks;
mcPlayer.dead = true;
}
@Override
public long getKeepAliveTime(final Player player) {
// TODO: Implement if possible.
return Long.MIN_VALUE;
}
@Override
public boolean hasGravity(final Material mat) {
// TODO: Test/check.
return mat.hasGravity();
}
// @Override
// public void correctDirection(final Player player) {
// final EntityPlayer mcPlayer = ((CraftPlayer) player).getHandle();
// // Main direction.
// mcPlayer.yaw = LocUtil.correctYaw(mcPlayer.yaw);
// mcPlayer.pitch = LocUtil.correctPitch(mcPlayer.pitch);
// // Consider setting the lastYaw here too.
// }
}

View File

@ -22,16 +22,17 @@
<dependency>
<groupId>org.bukkit</groupId>
<artifactId>craftbukkit</artifactId>
<version>1.7.2-R0.4-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.bukkit</groupId>
<artifactId>bukkit</artifactId>
<version>1.7.2-R0.4-SNAPSHOT</version>
<version>1.7.10-R0.1-SNAPSHOT</version>
</dependency>
</dependencies>
<description>Compatibility for the development version (latest of the supported Minecraft versions).
Version updating is done for the NoCheatPlus sub-module.</description>
Version updating is done for the NoCheatPlus sub-module.
To add a new compat module three other pom.xml files have to be modified:
- Root pom (parent): Add as module.
- NCPPlugin: Add as dependency.
- NochCheatPlus: Add as include (source).
</description>
</project>

View File

@ -3,16 +3,15 @@ package fr.neatmonster.nocheatplus.compat.cbdev;
import java.util.Iterator;
import java.util.List;
import net.minecraft.server.v1_7_R1.AxisAlignedBB;
import net.minecraft.server.v1_7_R1.Block;
import net.minecraft.server.v1_7_R1.EntityBoat;
import net.minecraft.server.v1_7_R1.IBlockAccess;
import net.minecraft.server.v1_7_R1.TileEntity;
import net.minecraft.server.v1_7_R1.Vec3DPool;
import net.minecraft.server.v1_7_R4.AxisAlignedBB;
import net.minecraft.server.v1_7_R4.Block;
import net.minecraft.server.v1_7_R4.EntityBoat;
import net.minecraft.server.v1_7_R4.IBlockAccess;
import net.minecraft.server.v1_7_R4.TileEntity;
import org.bukkit.World;
import org.bukkit.craftbukkit.v1_7_R1.CraftWorld;
import org.bukkit.craftbukkit.v1_7_R1.entity.CraftEntity;
import org.bukkit.craftbukkit.v1_7_R4.CraftWorld;
import org.bukkit.craftbukkit.v1_7_R4.entity.CraftEntity;
import org.bukkit.entity.Entity;
import fr.neatmonster.nocheatplus.utilities.BlockCache;
@ -22,7 +21,7 @@ public class BlockCacheCBDev extends BlockCache implements IBlockAccess{
/** Box for one time use, no nesting, no extra storing this(!). */
protected static final AxisAlignedBB useBox = AxisAlignedBB.a(0, 0, 0, 0, 0, 0);
protected net.minecraft.server.v1_7_R1.WorldServer world;
protected net.minecraft.server.v1_7_R4.WorldServer world;
public BlockCacheCBDev(World world) {
setAccess(world);
@ -30,7 +29,12 @@ public class BlockCacheCBDev extends BlockCache implements IBlockAccess{
@Override
public void setAccess(World world) {
this.world = world == null ? null : ((CraftWorld) world).getHandle();
if (world != null) {
this.maxBlockY = world.getMaxHeight() - 1;
this.world = ((CraftWorld) world).getHandle();
} else {
this.world = null;
}
}
@Override
@ -48,8 +52,10 @@ public class BlockCacheCBDev extends BlockCache implements IBlockAccess{
// TODO: change api for this / use nodes (!)
final int id = getTypeId(x, y, z);
final net.minecraft.server.v1_7_R1.Block block = net.minecraft.server.v1_7_R1.Block.e(id);
if (block == null) return null;
final net.minecraft.server.v1_7_R4.Block block = net.minecraft.server.v1_7_R4.Block.getById(id);
if (block == null) {
return null;
}
block.updateShape(this, x, y, z); // TODO: use THIS instead of world.
// minX, minY, minZ, maxX, maxY, maxZ
@ -61,7 +67,7 @@ public class BlockCacheCBDev extends BlockCache implements IBlockAccess{
try{
// TODO: Probably check other ids too before doing this ?
final net.minecraft.server.v1_7_R1.Entity mcEntity = ((CraftEntity) entity).getHandle();
final net.minecraft.server.v1_7_R4.Entity mcEntity = ((CraftEntity) entity).getHandle();
final AxisAlignedBB box = useBox.b(minX, minY, minZ, maxX, maxY, maxZ);
@SuppressWarnings("rawtypes")
@ -69,7 +75,7 @@ public class BlockCacheCBDev extends BlockCache implements IBlockAccess{
@SuppressWarnings("rawtypes")
final Iterator iterator = list.iterator();
while (iterator.hasNext()) {
final net.minecraft.server.v1_7_R1.Entity other = (net.minecraft.server.v1_7_R1.Entity) iterator.next();
final net.minecraft.server.v1_7_R4.Entity other = (net.minecraft.server.v1_7_R4.Entity) iterator.next();
if (!(other instanceof EntityBoat)){ // && !(other instanceof EntityMinecart)) continue;
continue;
}
@ -78,7 +84,9 @@ public class BlockCacheCBDev extends BlockCache implements IBlockAccess{
}
// Still check this for some reason.
final AxisAlignedBB otherBox = other.boundingBox;
if (box.a > otherBox.d || box.d < otherBox.a || box.b > otherBox.e || box.e < otherBox.b || box.c > otherBox.f || box.f < otherBox.c) continue;
if (box.a > otherBox.d || box.d < otherBox.a || box.b > otherBox.e || box.e < otherBox.b || box.c > otherBox.f || box.f < otherBox.c) {
continue;
}
else {
return true;
}
@ -104,11 +112,6 @@ public class BlockCacheCBDev extends BlockCache implements IBlockAccess{
return world.getTileEntity(x, y, z);
}
@Override
public Vec3DPool getVec3DPool() {
return world.getVec3DPool();
}
@Override
public int getBlockPower(final int arg0, final int arg1, final int arg2, final int arg3) {
return world.getBlockPower(arg0, arg1, arg2, arg3);

View File

@ -1,19 +1,19 @@
package fr.neatmonster.nocheatplus.compat.cbdev;
import net.minecraft.server.v1_7_R1.AxisAlignedBB;
import net.minecraft.server.v1_7_R1.Block;
import net.minecraft.server.v1_7_R1.DamageSource;
import net.minecraft.server.v1_7_R1.EntityComplexPart;
import net.minecraft.server.v1_7_R1.EntityPlayer;
import net.minecraft.server.v1_7_R1.MobEffectList;
import net.minecraft.server.v1_7_R4.AxisAlignedBB;
import net.minecraft.server.v1_7_R4.Block;
import net.minecraft.server.v1_7_R4.DamageSource;
import net.minecraft.server.v1_7_R4.EntityComplexPart;
import net.minecraft.server.v1_7_R4.EntityPlayer;
import net.minecraft.server.v1_7_R4.MobEffectList;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.command.CommandMap;
import org.bukkit.craftbukkit.v1_7_R1.CraftServer;
import org.bukkit.craftbukkit.v1_7_R1.entity.CraftEntity;
import org.bukkit.craftbukkit.v1_7_R1.entity.CraftPlayer;
import org.bukkit.craftbukkit.v1_7_R4.CraftServer;
import org.bukkit.craftbukkit.v1_7_R4.entity.CraftEntity;
import org.bukkit.craftbukkit.v1_7_R4.entity.CraftPlayer;
import org.bukkit.entity.Entity;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player;
@ -28,24 +28,24 @@ public class MCAccessCBDev implements MCAccess{
/**
* Constructor to let it fail.
*/
public MCAccessCBDev(){
public MCAccessCBDev() {
getCommandMap();
ReflectionUtil.checkMembers("net.minecraft.server.v1_7_R1.", new String[]{"Entity" , "dead"});
ReflectionUtil.checkMembers("net.minecraft.server.v1_7_R4.", new String[] {"Entity" , "dead"});
// block bounds, original: minX, maxX, minY, maxY, minZ, maxZ
ReflectionUtil.checkMethodReturnTypesNoArgs(net.minecraft.server.v1_7_R1.Block.class,
ReflectionUtil.checkMethodReturnTypesNoArgs(net.minecraft.server.v1_7_R4.Block.class,
new String[]{"x", "y", "z", "A", "B", "C"}, double.class);
// TODO: Nail it down further.
}
@Override
public String getMCVersion() {
// 1_7_R1
return "1.7.2";
// 1_7_R4
return "1.7.10";
}
@Override
public String getServerVersionTag() {
return "CB2922-DEV";
return "CB3100-DEV";
}
@Override
@ -60,7 +60,7 @@ public class MCAccessCBDev implements MCAccess{
@Override
public double getHeight(final Entity entity) {
final net.minecraft.server.v1_7_R1.Entity mcEntity = ((CraftEntity) entity).getHandle();
final net.minecraft.server.v1_7_R4.Entity mcEntity = ((CraftEntity) entity).getHandle();
final double entityHeight = Math.max(mcEntity.length, Math.max(mcEntity.height, mcEntity.boundingBox.e - mcEntity.boundingBox.b));
if (entity instanceof LivingEntity) {
return Math.max(((LivingEntity) entity).getEyeHeight(), entityHeight);
@ -69,16 +69,24 @@ public class MCAccessCBDev implements MCAccess{
@Override
public AlmostBoolean isBlockSolid(final int id) {
final Block block = Block.e(id);
if (block == null || block.getMaterial() == null) return AlmostBoolean.MAYBE;
else return AlmostBoolean.match(block.getMaterial().isSolid());
final Block block = Block.getById(id);
if (block == null || block.getMaterial() == null) {
return AlmostBoolean.MAYBE;
}
else {
return AlmostBoolean.match(block.getMaterial().isSolid());
}
}
@Override
public AlmostBoolean isBlockLiquid(final int id) {
final Block block = Block.e(id);
if (block == null || block.getMaterial() == null) return AlmostBoolean.MAYBE;
else return AlmostBoolean.match(block.getMaterial().isLiquid());
final Block block = Block.getById(id);
if (block == null || block.getMaterial() == null) {
return AlmostBoolean.MAYBE;
}
else {
return AlmostBoolean.match(block.getMaterial().isLiquid());
}
}
@Override
@ -89,31 +97,44 @@ public class MCAccessCBDev implements MCAccess{
@Override
public AlmostBoolean isIllegalBounds(final Player player) {
final EntityPlayer entityPlayer = ((CraftPlayer) player).getHandle();
if (entityPlayer.dead) return AlmostBoolean.NO;
if (entityPlayer.dead) {
return AlmostBoolean.NO;
}
// TODO: Does this need a method call for the "real" box? Might be no problem during moving events, though.
final AxisAlignedBB box = entityPlayer.boundingBox;
if (!entityPlayer.isSleeping()){
if (!entityPlayer.isSleeping()) {
// This can not really test stance but height of bounding box.
final double dY = Math.abs(box.e - box.b);
if (dY > 1.8) return AlmostBoolean.YES; // dY > 1.65D ||
if (dY < 0.1D && entityPlayer.length >= 0.1) return AlmostBoolean.YES;
if (dY > 1.8) {
return AlmostBoolean.YES; // dY > 1.65D ||
}
if (dY < 0.1D && entityPlayer.length >= 0.1) {
return AlmostBoolean.YES;
}
}
return AlmostBoolean.MAYBE;
}
@Override
public double getJumpAmplifier(final Player player) {
final net.minecraft.server.v1_7_R1.EntityPlayer mcPlayer = ((CraftPlayer) player).getHandle();
if (mcPlayer.hasEffect(MobEffectList.JUMP)) return mcPlayer.getEffect(MobEffectList.JUMP).getAmplifier();
else return Double.NEGATIVE_INFINITY;
final EntityPlayer mcPlayer = ((CraftPlayer) player).getHandle();
if (mcPlayer.hasEffect(MobEffectList.JUMP)) {
return mcPlayer.getEffect(MobEffectList.JUMP).getAmplifier();
}
else {
return Double.NEGATIVE_INFINITY;
}
}
@Override
public double getFasterMovementAmplifier(final Player player) {
final net.minecraft.server.v1_7_R1.EntityPlayer mcPlayer = ((CraftPlayer) player).getHandle();
if (mcPlayer.hasEffect(MobEffectList.FASTER_MOVEMENT)) return mcPlayer.getEffect(MobEffectList.FASTER_MOVEMENT).getAmplifier();
else return Double.NEGATIVE_INFINITY;
final EntityPlayer mcPlayer = ((CraftPlayer) player).getHandle();
if (mcPlayer.hasEffect(MobEffectList.FASTER_MOVEMENT)) {
return mcPlayer.getEffect(MobEffectList.FASTER_MOVEMENT).getAmplifier();
}
else {
return Double.NEGATIVE_INFINITY;
}
}
@Override
@ -138,13 +159,13 @@ public class MCAccessCBDev implements MCAccess{
@Override
public boolean shouldBeZombie(final Player player) {
final net.minecraft.server.v1_7_R1.EntityPlayer mcPlayer = ((CraftPlayer) player).getHandle();
final EntityPlayer mcPlayer = ((CraftPlayer) player).getHandle();
return !mcPlayer.dead && mcPlayer.getHealth() <= 0.0f ;
}
@Override
public void setDead(final Player player, final int deathTicks) {
final net.minecraft.server.v1_7_R1.EntityPlayer mcPlayer = ((CraftPlayer) player).getHandle();
final EntityPlayer mcPlayer = ((CraftPlayer) player).getHandle();
mcPlayer.deathTicks = deathTicks;
mcPlayer.dead = true;
}
@ -161,4 +182,13 @@ public class MCAccessCBDev implements MCAccess{
return mat.hasGravity();
}
// @Override
// public void correctDirection(final Player player) {
// final EntityPlayer mcPlayer = ((CraftPlayer) player).getHandle();
// // Main direction.
// mcPlayer.yaw = LocUtil.correctYaw(mcPlayer.yaw);
// mcPlayer.pitch = LocUtil.correctPitch(mcPlayer.pitch);
// // Consider setting the lastYaw here too.
// }
}

View File

@ -0,0 +1,39 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>fr.neatmonster</groupId>
<artifactId>ncpcompatprotocollib</artifactId>
<packaging>jar</packaging>
<name>NCPCompatProtocolLib</name>
<version>static</version>
<parent>
<groupId>fr.neatmonster</groupId>
<artifactId>nocheatplus-parent</artifactId>
<version>static</version>
</parent>
<repositories>
<repository>
<id>comphenix-rep</id>
<name>Comphenix Repository</name>
<url>http://repo.comphenix.net/content/groups/public</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>fr.neatmonster</groupId>
<artifactId>ncpcore</artifactId>
<version>static</version>
</dependency>
<dependency>
<groupId>com.comphenix.protocol</groupId>
<artifactId>ProtocolLib</artifactId>
<version>LATEST</version>
</dependency>
</dependencies>
<description>Features using the plugin ProtocolLib:
http://dev.bukkit.org/bukkit-plugins/protocollib/</description>
</project>

View File

@ -0,0 +1,91 @@
package fr.neatmonster.nocheatplus.net.protocollib;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import org.bukkit.entity.Player;
import org.bukkit.event.Listener;
import org.bukkit.plugin.Plugin;
import com.comphenix.protocol.PacketType;
import com.comphenix.protocol.PacketType.Protocol;
import com.comphenix.protocol.PacketType.Sender;
import com.comphenix.protocol.events.PacketAdapter;
import com.comphenix.protocol.events.PacketEvent;
import fr.neatmonster.nocheatplus.components.JoinLeaveListener;
import fr.neatmonster.nocheatplus.utilities.ActionFrequency;
/**
* Prevent extremely fast ticking by just sending packets that don't do anything
* new and also don't trigger moving events in CraftBukkit.
*
* @author dev1mc
*
*/
public class MoveFrequency extends PacketAdapter implements Listener, JoinLeaveListener {
// TODO: Optimized options (receive only, other?).
// TODO: Async version ?
// private static Collection<PacketType> getPacketTypes() {
// final Collection<PacketType> packetTypes = PacketType.fromName("C03PacketPlayer");
// if (packetTypes.isEmpty()) {
// throw new RuntimeException("Packet types not available.");
// }
// return packetTypes;
// }
private Map<String, ActionFrequency> freqMap = new LinkedHashMap<String, ActionFrequency>();
public MoveFrequency(Plugin plugin) {
// PacketPlayInFlying[3, legacy: 10]
super(plugin, PacketType.findCurrent(Protocol.PLAY, Sender.CLIENT, 3)); //getPacketTypes());
// TODO: Try to get packet by name first + legacy first.
}
private ActionFrequency addName(String name) {
Map<String, ActionFrequency> freqMap = new HashMap<String, ActionFrequency>(this.freqMap);
ActionFrequency freq = new ActionFrequency(5, 1000);
freqMap.put(name, freq);
this.freqMap = freqMap;
return freq;
}
private void removeName(String name) {
Map<String, ActionFrequency> freq = new HashMap<String, ActionFrequency>(this.freqMap);
freq.remove(name);
this.freqMap = freq;
}
@Override
public void playerJoins(Player player) {
addName(player.getName()); // Could spare that one.
}
@Override
public void playerLeaves(Player player) {
removeName(player.getName());
}
private ActionFrequency getFreq(String name) {
ActionFrequency freq = this.freqMap.get(name);
if (freq == null) {
return addName(name);
} else {
return freq;
}
}
@Override
public void onPacketReceiving(PacketEvent event) {
// TODO: Add several (at least has look + has pos individually, maybe none/onground)
ActionFrequency freq = getFreq(event.getPlayer().getName());
freq.add(System.currentTimeMillis(), 1f);
if (freq.score(1f) > 300) {
event.setCancelled(true);
}
}
}

View File

@ -0,0 +1,54 @@
package fr.neatmonster.nocheatplus.net.protocollib;
import java.util.LinkedList;
import java.util.List;
import org.bukkit.plugin.Plugin;
import com.comphenix.protocol.ProtocolLibrary;
import com.comphenix.protocol.ProtocolManager;
import com.comphenix.protocol.events.PacketAdapter;
import fr.neatmonster.nocheatplus.components.DisableListener;
import fr.neatmonster.nocheatplus.logging.LogUtil;
/**
* Quick and dirty ProtocolLib setup.
* @author dev1mc
*
*/
public class ProtocolLibComponent implements DisableListener{
private final List<PacketAdapter> registeredPacketAdapters = new LinkedList<PacketAdapter>();
public ProtocolLibComponent(Plugin plugin) {
// Register with ProtocolLib
final ProtocolManager protocolManager = ProtocolLibrary.getProtocolManager();
LogUtil.logInfo("[NoCheatPlus] ProtocolLib seems to be available.");
try {
PacketAdapter adapter = new MoveFrequency(plugin);
protocolManager.addPacketListener(adapter);
registeredPacketAdapters.add(adapter);
} catch (Throwable t) {
LogUtil.logWarning("[NoCheatPlus] Could not register some packet-level hook.");
LogUtil.logWarning(t); // TODO: Maybe temporary.
}
}
@Override
public void onDisable() {
final ProtocolManager protocolManager = ProtocolLibrary.getProtocolManager();
for (PacketAdapter adapter : registeredPacketAdapters) {
try {
protocolManager.removePacketListener(adapter);
} catch (Throwable t) {
LogUtil.logWarning("[NoCheatPlus] Failed to unregister protocol listener: " + adapter.getClass().getName());
}
}
}
}

View File

@ -17,7 +17,7 @@
<dependency>
<groupId>org.bukkit</groupId>
<artifactId>bukkit</artifactId>
<version>1.7.2-R0.4-SNAPSHOT</version>
<version>1.7.9-R0.2</version>
</dependency>
<dependency>
<groupId>fr.neatmonster</groupId>

View File

@ -4,19 +4,22 @@ package fr.neatmonster.nocheatplus.actions;
* Some wildcards that are used in commands and log messages.
*/
public enum ParameterName {
// TODO: Cleanup for some kind of policies: useful names, alternative names, prefer generic names.
BLOCK_ID("blockid"),
BLOCK_TYPE("blocktype"),
CHECK("check"),
TAGS("tags"),
DISTANCE("distance"),
FALL_DISTANCE("falldistance"),
FALL_DISTANCE("falldistance"), // TODO: rather not deprecate ?
FOOD("food"),
IP("ip"),
LIMIT("limit"),
LOCATION_FROM("locationfrom"),
LOCATION_TO("locationto"),
PACKETS("packets"),
PLAYER("player"),
REACH_DISTANCE("reachdistance"),
PLAYER("player"), // TODO: playername rather ? + displayname ?
REACH_DISTANCE("reachdistance"), // TODO: deprecate ?
UUID("uuid"),
VIOLATIONS("violations"),
WORLD("world");

View File

@ -135,6 +135,8 @@ public class ViolationData implements IViolationInfo, ActionData{
return player.getName();
case VIOLATIONS:
return String.valueOf((long) Math.round(vL));
case UUID:
return player.getUniqueId().toString();
default:
break;
}

View File

@ -65,7 +65,6 @@ public class BlockBreakConfig extends ACheckConfig {
public final long fastBreakGrace;
public final long fastBreakDelay;
public final int fastBreakModSurvival;
public final int fastBreakModCreative;
public final ActionList fastBreakActions;
@ -112,7 +111,6 @@ public class BlockBreakConfig extends ACheckConfig {
fastBreakBucketDur = data.getInt(ConfPaths.BLOCKBREAK_FASTBREAK_BUCKETS_DUR, 4000);
fastBreakBucketFactor = (float) data.getDouble(ConfPaths.BLOCKBREAK_FASTBREAK_BUCKETS_FACTOR, 0.99);
fastBreakBuckets = data.getInt(ConfPaths.BLOCKBREAK_FASTBREAK_BUCKETS_N, 30);
fastBreakModCreative = data.getInt(ConfPaths.BLOCKBREAK_FASTBREAK_MOD_CREATIVE, 0);
fastBreakModSurvival = data.getInt(ConfPaths.BLOCKBREAK_FASTBREAK_MOD_SURVIVAL);
// Fastbreak actions, shared.
fastBreakActions = data.getOptimizedActionList(ConfPaths.BLOCKBREAK_FASTBREAK_ACTIONS, Permissions.BLOCKBREAK_FASTBREAK);

View File

@ -18,6 +18,7 @@ import org.bukkit.inventory.ItemStack;
import fr.neatmonster.nocheatplus.checks.CheckListener;
import fr.neatmonster.nocheatplus.checks.CheckType;
import fr.neatmonster.nocheatplus.checks.inventory.Items;
import fr.neatmonster.nocheatplus.compat.AlmostBoolean;
import fr.neatmonster.nocheatplus.hooks.NCPExemptionManager;
import fr.neatmonster.nocheatplus.permissions.Permissions;
import fr.neatmonster.nocheatplus.utilities.BlockProperties;
@ -48,7 +49,7 @@ public class BlockBreakListener extends CheckListener {
/** The wrong block check. */
private final WrongBlock wrongBlock = addCheck(new WrongBlock());
private boolean isInstaBreak = false;
private AlmostBoolean isInstaBreak = AlmostBoolean.NO;
public BlockBreakListener(){
super(CheckType.BLOCKBREAK);
@ -60,18 +61,19 @@ public class BlockBreakListener extends CheckListener {
* @param event
* the event
*/
@EventHandler(
ignoreCancelled = false, priority = EventPriority.LOWEST)
@EventHandler(ignoreCancelled = false, priority = EventPriority.LOWEST)
public void onBlockBreak(final BlockBreakEvent event) {
final Player player = event.getPlayer();
// Illegal enchantments hotfix check.
if (Items.checkIllegalEnchantments(player, player.getItemInHand())) event.setCancelled(true);
if (Items.checkIllegalEnchantments(player, player.getItemInHand())) {
event.setCancelled(true);
}
// Cancelled events only leads to resetting insta break.
if (event.isCancelled()){
isInstaBreak = false;
if (event.isCancelled()) {
isInstaBreak = AlmostBoolean.NO;
return;
}
@ -92,38 +94,45 @@ public class BlockBreakListener extends CheckListener {
final GameMode gameMode = player.getGameMode();
// Has the player broken a block that was not damaged before?
if (wrongBlock.isEnabled(player) && wrongBlock.check(player, block, cc, data, isInstaBreak))
if (wrongBlock.isEnabled(player) && wrongBlock.check(player, block, cc, data, isInstaBreak)) {
cancelled = true;
}
// Has the player broken more blocks per second than allowed?
if (!cancelled && frequency.isEnabled(player) && frequency.check(player, cc, data))
if (!cancelled && frequency.isEnabled(player) && frequency.check(player, cc, data)) {
cancelled = true;
}
// Has the player broken blocks faster than possible?
if (!cancelled && gameMode != GameMode.CREATIVE && fastBreak.isEnabled(player) && fastBreak.check(player, block, isInstaBreak, cc, data))
cancelled = true;
if (!cancelled && gameMode != GameMode.CREATIVE && fastBreak.isEnabled(player) && fastBreak.check(player, block, isInstaBreak, cc, data)) {
cancelled = true;
}
// Did the arm of the player move before breaking this block?
if (!cancelled && noSwing.isEnabled(player) && noSwing.check(player, data))
cancelled = true;
if (!cancelled && noSwing.isEnabled(player) && noSwing.check(player, data)) {
cancelled = true;
}
// Is the block really in reach distance?
if (!cancelled && reach.isEnabled(player) && reach.check(player, block, data))
cancelled = true;
if (!cancelled && reach.isEnabled(player) && reach.check(player, block, data)) {
cancelled = true;
}
// Did the player look at the block at all?
if (!cancelled && direction.isEnabled(player) && direction.check(player, block, data))
cancelled = true;
if (!cancelled && direction.isEnabled(player) && direction.check(player, block, data)) {
cancelled = true;
}
// Destroying liquid blocks.
if (!cancelled && BlockProperties.isLiquid(block.getTypeId()) && !player.hasPermission(Permissions.BLOCKBREAK_BREAK_LIQUID) && !NCPExemptionManager.isExempted(player, CheckType.BLOCKBREAK_BREAK)){
if (!cancelled && BlockProperties.isLiquid(block.getType()) && !player.hasPermission(Permissions.BLOCKBREAK_BREAK_LIQUID) && !NCPExemptionManager.isExempted(player, CheckType.BLOCKBREAK_BREAK)){
cancelled = true;
}
// At least one check failed and demanded to cancel the event.
if (cancelled){
// On cancel...
if (cancelled) {
event.setCancelled(cancelled);
// Reset damage position:
// TODO: Review this (!), check if set at all !?
data.clickedX = block.getX();
data.clickedY = block.getY();
data.clickedZ = block.getZ();
@ -133,16 +142,17 @@ public class BlockBreakListener extends CheckListener {
// data.clickedX = Integer.MAX_VALUE;
}
if (isInstaBreak){
if (isInstaBreak.decideOptimistically()) {
data.wasInstaBreak = now;
}
else
else {
data.wasInstaBreak = 0;
}
// Adjust data.
data.fastBreakBreakTime = now;
// data.fastBreakfirstDamage = now;
isInstaBreak = false;
isInstaBreak = AlmostBoolean.NO;
}
/**
@ -175,18 +185,32 @@ public class BlockBreakListener extends CheckListener {
// Return if it is not left clicking a block.
// (Allows right click to be ignored.)
isInstaBreak = false;
if (event.getAction() != Action.LEFT_CLICK_BLOCK) return;
isInstaBreak = AlmostBoolean.NO;
if (event.getAction() != Action.LEFT_CLICK_BLOCK) {
return;
}
checkBlockDamage(event.getPlayer(), event.getClickedBlock(), event);
}
@EventHandler(
ignoreCancelled = false, priority = EventPriority.MONITOR)
@EventHandler(ignoreCancelled = false, priority = EventPriority.LOWEST)
public void onBlockDamageLowest(final BlockDamageEvent event) {
if (event.getInstaBreak()) {
// Indicate that this might have been set by CB/MC.
isInstaBreak = AlmostBoolean.MAYBE;
}
}
@EventHandler(ignoreCancelled = false, priority = EventPriority.MONITOR)
public void onBlockDamage(final BlockDamageEvent event) {
// System.out.println("Damage("+event.isCancelled()+"): " + event.getBlock());
if (!event.isCancelled() && event.getInstaBreak()) isInstaBreak = true;
else isInstaBreak = false;
if (!event.isCancelled() && event.getInstaBreak()) {
// Keep MAYBE.
if (isInstaBreak != AlmostBoolean.MAYBE) {
isInstaBreak = AlmostBoolean.YES;
}
}
else {
isInstaBreak = AlmostBoolean.NO;
}
checkBlockDamage(event.getPlayer(), event.getBlock(), event);
}
@ -202,8 +226,9 @@ public class BlockBreakListener extends CheckListener {
// }
// Do not care about null blocks.
if (block == null)
return;
if (block == null) {
return;
}
final int tick = TickTask.getTick();
// Skip if already set to the same block without breaking within one tick difference.
@ -211,10 +236,14 @@ public class BlockBreakListener extends CheckListener {
final Material tool = stack == null ? null: stack.getType();
if (data.toolChanged(tool)) {
// Update.
} else if (tick < data.clickedTick) {
// Update.
} else if (tick < data.clickedTick || now < data.fastBreakfirstDamage || now < data.fastBreakBreakTime) {
// Time/tick ran backwards: Update.
// Tick running backwards should not happen in the main thread unless for reload. A plugin could reset it (not intended).
} else if (data.fastBreakBreakTime < data.fastBreakfirstDamage && data.clickedX == block.getX() && data.clickedZ == block.getZ() && data.clickedY == block.getY()){
if (tick - data.clickedTick <= 1 ) return;
// Preserve first damage time.
if (tick - data.clickedTick <= 1 ) {
return;
}
}
// (Always set, the interact event only fires once: the first time.)
// Only record first damage:

View File

@ -13,6 +13,9 @@ import fr.neatmonster.nocheatplus.utilities.TrigUtil;
* The Direction check will find out if a player tried to interact with something that's not in their field of view.
*/
public class Direction extends Check {
/** For temporary use: LocUtil.clone before passing deeply, call setWorld(null) after use. */
private final Location useLoc = new Location(null, 0, 0, 0);
/**
* Instantiates a new direction check.
@ -36,7 +39,7 @@ public class Direction extends Check {
// How far "off" is the player with their aim. We calculate from the players eye location and view direction to
// the center of the target block. If the line of sight is more too far off, "off" will be bigger than 0.
final Location loc = player.getLocation();
final Location loc = player.getLocation(useLoc);
final Vector direction = loc.getDirection();
final double off = TrigUtil.directionCheck(loc, player.getEyeHeight(), direction, block, TrigUtil.DIRECTION_PRECISION);
@ -52,10 +55,11 @@ public class Direction extends Check {
// cancel the event.
cancel = executeActions(player, data.directionVL, distance,
BlockBreakConfig.getConfig(player).directionActions);
} else
} else {
// Player did likely nothing wrong, reduce violation counter to reward them.
data.directionVL *= 0.9D;
}
useLoc.setWorld(null);
return cancel;
}
}

View File

@ -1,6 +1,6 @@
package fr.neatmonster.nocheatplus.checks.blockbreak;
import org.bukkit.GameMode;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
@ -10,6 +10,7 @@ import fr.neatmonster.nocheatplus.actions.ParameterName;
import fr.neatmonster.nocheatplus.checks.Check;
import fr.neatmonster.nocheatplus.checks.CheckType;
import fr.neatmonster.nocheatplus.checks.ViolationData;
import fr.neatmonster.nocheatplus.compat.AlmostBoolean;
import fr.neatmonster.nocheatplus.permissions.Permissions;
import fr.neatmonster.nocheatplus.utilities.BlockProperties;
import fr.neatmonster.nocheatplus.utilities.PotionUtil;
@ -28,7 +29,7 @@ public class FastBreak extends Check {
}
/**
* Checks a player.
* Checks a player for fastbreak. This is NOT for creative mode.
*
* @param player
* the player
@ -40,84 +41,83 @@ public class FastBreak extends Check {
* @param elaspedTime
* @return true, if successful
*/
public boolean check(final Player player, final Block block, final boolean isInstaBreak, final BlockBreakConfig cc, final BlockBreakData data) {
public boolean check(final Player player, final Block block, final AlmostBoolean isInstaBreak, final BlockBreakConfig cc, final BlockBreakData data) {
final long now = System.currentTimeMillis();
boolean cancel = false;
// First, check the game mode of the player and choose the right limit.
final long breakingTime;
final int id = block.getTypeId();
if (player.getGameMode() == GameMode.CREATIVE)
// Modifier defaults to 0, the Frequency check is responsible for those.
breakingTime = Math.max(0, Math.round((double) cc.fastBreakModCreative / 100D * (double) 100));
else
breakingTime = Math.max(0, Math.round((double) cc.fastBreakModSurvival / 100D * (double) BlockProperties.getBreakingDuration(id, player)));
// fastBreakfirstDamage is the first interact on block (!).
// Determine expected breaking time by block type.
final Material blockType = block.getType();
final long expectedBreakingTime = Math.max(0, Math.round((double) BlockProperties.getBreakingDuration(blockType, player) * (double) cc.fastBreakModSurvival / 100D));
final long elapsedTime;
// TODO: Concept for unbreakable blocks? Context: extreme VL.
// TODO: Should it be breakingTime instead of 0 for inconsistencies?
if (cc.fastBreakStrict){
if (cc.fastBreakStrict) {
// Counting interact...break.
elapsedTime = (data.fastBreakBreakTime > data.fastBreakfirstDamage) ? 0 : now - data.fastBreakfirstDamage;
}
else{
else {
// Counting break...break.
elapsedTime = (data.fastBreakBreakTime > now) ? 0 : now - data.fastBreakBreakTime;
}
// Check if the time used time is lower than expected.
// if (isInstaBreak){
// // Ignore those for now.
// }
// else
if (elapsedTime < 0){
if (isInstaBreak.decideOptimistically()) {
// Ignore those for now.
// TODO: Find out why this was commented out long ago a) did not fix mcMMO b) exploits.
// TODO: Maybe adjust time to min(time, SOMETHING) for MAYBE/YES.
}
else if (elapsedTime < 0) {
// Ignore it. TODO: ?
}
else if (elapsedTime + cc.fastBreakDelay < breakingTime){
else if (elapsedTime + cc.fastBreakDelay < expectedBreakingTime) {
// lag or cheat or Minecraft.
// Count in server side lag, if desired.
final float lag = cc.lag ? TickTask.getLag(breakingTime, true) : 1f;
final float lag = cc.lag ? TickTask.getLag(expectedBreakingTime, true) : 1f;
final long missingTime = breakingTime - (long) (lag * elapsedTime);
final long missingTime = expectedBreakingTime - (long) (lag * elapsedTime);
if (missingTime > 0){
if (missingTime > 0) {
// Add as penalty
data.fastBreakPenalties.add(now, (float) missingTime);
// Only raise a violation, if the total penalty score exceeds the contention duration (for lag, delay).
if (data.fastBreakPenalties.score(cc.fastBreakBucketFactor) > cc.fastBreakGrace){
if (data.fastBreakPenalties.score(cc.fastBreakBucketFactor) > cc.fastBreakGrace) {
// TODO: maybe add one absolute penalty time for big amounts to stop breaking until then
final double vlAdded = (double) missingTime / 1000.0;
data.fastBreakVL += vlAdded;
final ViolationData vd = new ViolationData(this, player, data.fastBreakVL, vlAdded, cc.fastBreakActions);
if (vd.needsParameters()) vd.setParameter(ParameterName.BLOCK_ID, "" + id);
if (vd.needsParameters()) {
vd.setParameter(ParameterName.BLOCK_TYPE, blockType.toString());
vd.setParameter(ParameterName.BLOCK_ID, Integer.toString(BlockProperties.getId(blockType)));
}
cancel = executeActions(vd);
}
// else: still within contention limits.
}
}
else if (breakingTime > cc.fastBreakDelay){
else if (expectedBreakingTime > cc.fastBreakDelay) {
// Fast breaking does not decrease violation level.
data.fastBreakVL *= 0.9D;
}
if ((cc.fastBreakDebug || cc.debug) && player.hasPermission(Permissions.ADMINISTRATION_DEBUG)){
if ((cc.fastBreakDebug || cc.debug) && player.hasPermission(Permissions.ADMINISTRATION_DEBUG)) {
// General stats:
if (data.stats != null){
data.stats.addStats(data.stats.getId(Integer.toString(block.getTypeId())+"u", true), elapsedTime);
data.stats.addStats(data.stats.getId(Integer.toString(block.getTypeId())+ "r", true), breakingTime);
if (data.stats != null) {
data.stats.addStats(data.stats.getId(blockType+ "/u", true), elapsedTime);
data.stats.addStats(data.stats.getId(blockType + "/r", true), expectedBreakingTime);
player.sendMessage(data.stats.getStatsStr(true));
}
// Send info about current break:
final int blockId = block.getTypeId();
final ItemStack stack = player.getItemInHand();
final boolean isValidTool = BlockProperties.isValidTool(blockId, stack);
final boolean isValidTool = BlockProperties.isValidTool(blockType, stack);
final double haste = PotionUtil.getPotionEffectAmplifier(player, PotionEffectType.FAST_DIGGING);
String msg = (isInstaBreak ? "[Insta]" : "[Normal]") + "[" + blockId + "] "+ elapsedTime + "u / " + breakingTime +"r (" + (isValidTool?"tool":"no-tool") + ")" + (haste == Double.NEGATIVE_INFINITY ? "" : " haste=" + ((int) haste + 1));
String msg = (isInstaBreak.decideOptimistically() ? ("[Insta=" + isInstaBreak + "]") : "[Normal]") + "[" + blockType + "] "+ elapsedTime + "u / " + expectedBreakingTime +"r (" + (isValidTool?"tool":"no-tool") + ")" + (haste == Double.NEGATIVE_INFINITY ? "" : " haste=" + ((int) haste + 1));
player.sendMessage(msg);
// net.minecraft.server.Item mcItem = net.minecraft.server.Item.byId[stack.getTypeId()];
// if (mcItem != null){
// if (mcItem != null) {
// double x = mcItem.getDestroySpeed(((CraftItemStack) stack).getHandle(), net.minecraft.server.Block.byId[blockId]);
// player.sendMessage("mc speed: " + x);
// }

View File

@ -3,6 +3,7 @@ package fr.neatmonster.nocheatplus.checks.blockbreak;
import java.util.Map;
import org.bukkit.GameMode;
import org.bukkit.Location;
import org.bukkit.block.Block;
import org.bukkit.entity.Player;
@ -16,6 +17,9 @@ import fr.neatmonster.nocheatplus.utilities.TrigUtil;
* The Reach check will find out if a player interacts with something that's too far away.
*/
public class Reach extends Check {
/** For temporary use: LocUtil.clone before passing deeply, call setWorld(null) after use. */
private final Location useLoc = new Location(null, 0, 0, 0);
/** The maximum distance allowed to interact with a block in creative mode. */
public static final double CREATIVE_DISTANCE = 5.6D;
@ -47,7 +51,10 @@ public class Reach extends Check {
// Distance is calculated from eye location to center of targeted block. If the player is further away from their
// target than allowed, the difference will be assigned to "distance".
final double distance = TrigUtil.distance(player.getEyeLocation(), block) - distanceLimit;
final Location loc = player.getLocation(useLoc);
loc.setY(loc.getY() + player.getEyeHeight());
final double distance = TrigUtil.distance(loc, block) - distanceLimit;
useLoc.setWorld(null);
if (distance > 0) {
// They failed, increment violation level.

View File

@ -6,6 +6,7 @@ import org.bukkit.entity.Player;
import fr.neatmonster.nocheatplus.checks.Check;
import fr.neatmonster.nocheatplus.checks.CheckType;
import fr.neatmonster.nocheatplus.checks.combined.Improbable;
import fr.neatmonster.nocheatplus.compat.AlmostBoolean;
import fr.neatmonster.nocheatplus.permissions.Permissions;
import fr.neatmonster.nocheatplus.utilities.TrigUtil;
@ -26,45 +27,50 @@ public class WrongBlock extends Check {
* @param isInstaBreak
* @return
*/
public boolean check(final Player player, final Block block, final BlockBreakConfig cc, final BlockBreakData data, final boolean isInstaBreak){
public boolean check(final Player player, final Block block, final BlockBreakConfig cc, final BlockBreakData data, final AlmostBoolean isInstaBreak) {
boolean cancel = false;
final boolean wrongTime = data.fastBreakfirstDamage < data.fastBreakBreakTime;
final int dist = TrigUtil.manhattan(data.clickedX, data.clickedY, data.clickedZ, block);
final int dist = Math.min(4, data.clickedX == Integer.MAX_VALUE ? 100 : TrigUtil.manhattan(data.clickedX, data.clickedY, data.clickedZ, block));
final boolean wrongBlock;
final long now = System.currentTimeMillis();
if (dist == 0){
if (wrongTime){
// TODO: Remove isInstaBreak argument or use it.
if (dist == 0) {
if (wrongTime) {
data.fastBreakBreakTime = now;
data.fastBreakfirstDamage = now;
// Could set to wrong block, but prefer to transform it into a quasi insta break.
}
wrongBlock = false;
}
else if (dist == 1){
else if (dist == 1) {
// One might to a concession in case of instant breaking.
if (now - data.wasInstaBreak < 60)
if (now - data.wasInstaBreak < 60) {
wrongBlock = false;
else
}
else {
wrongBlock = true;
}
}
else
else {
// Note that the maximally counted distance is set above.
wrongBlock = true;
}
if (wrongBlock){
// Manhattan distance.
if ((cc.fastBreakDebug || cc.debug) && player.hasPermission(Permissions.ADMINISTRATION_DEBUG)){
if (wrongBlock) {
if ((cc.fastBreakDebug || cc.debug) && player.hasPermission(Permissions.ADMINISTRATION_DEBUG)) {
player.sendMessage("WrongBlock failure with dist: " + dist);
}
data.wrongBlockVL.add(now, (float) (dist + 1) / 2f);
final float score = data.wrongBlockVL.score(0.9f);
if (score > cc.wrongBLockLevel){
if (executeActions(player, score, 1D, cc.wrongBlockActions))
if (score > cc.wrongBLockLevel) {
if (executeActions(player, score, 1D, cc.wrongBlockActions)) {
cancel = true;
if (Improbable.check(player, 2.0f, now, "blockbreak.wrongblock"))
}
if (Improbable.check(player, 2.0f, now, "blockbreak.wrongblock")) {
cancel = true;
}
}
}

View File

@ -15,6 +15,7 @@ import org.bukkit.inventory.ItemStack;
import fr.neatmonster.nocheatplus.checks.CheckListener;
import fr.neatmonster.nocheatplus.checks.CheckType;
import fr.neatmonster.nocheatplus.checks.combined.CombinedConfig;
import fr.neatmonster.nocheatplus.compat.BridgeHealth;
import fr.neatmonster.nocheatplus.utilities.BlockProperties;
/**
@ -36,6 +37,9 @@ public class BlockInteractListener extends CheckListener {
/** Speed of interaction. */
private final Speed speed = addCheck(new Speed());
/** For temporary use: LocUtil.clone before passing deeply, call setWorld(null) after use. */
private final Location useLoc = new Location(null, 0, 0, 0);
public BlockInteractListener(){
super(CheckType.BLOCKINTERACT);
}
@ -49,6 +53,15 @@ public class BlockInteractListener extends CheckListener {
@EventHandler(
ignoreCancelled = false, priority = EventPriority.LOWEST)
protected void onPlayerInteract(final PlayerInteractEvent event) {
final Player player = event.getPlayer();
// Cancel interact events for dead players.
if (player.isDead() && BridgeHealth.getHealth(player) <= 0.0) {
// Auto-soup after death.
event.setUseInteractedBlock(Result.DENY);
event.setUseItemInHand(Result.DENY);
event.setCancelled(true);
return;
}
// TODO: Re-arrange for interact spam, possibly move ender pearl stuff to a method.
final Action action = event.getAction();
@ -57,7 +70,7 @@ public class BlockInteractListener extends CheckListener {
if (block == null){
return;
}
final Player player = event.getPlayer();
final BlockInteractData data = BlockInteractData.getData(player);
data.setLastBlock(block, action);
switch(action){
@ -65,8 +78,8 @@ public class BlockInteractListener extends CheckListener {
break;
case RIGHT_CLICK_BLOCK:
final ItemStack stack = player.getItemInHand();
if (stack != null && stack.getTypeId() == Material.ENDER_PEARL.getId()){
if (!BlockProperties.isPassable(block.getTypeId())){
if (stack != null && stack.getType() == Material.ENDER_PEARL){
if (!BlockProperties.isPassable(block.getType())){
final CombinedConfig ccc = CombinedConfig.getConfig(player);
if (ccc.enderPearlCheck && ccc.enderPearlPreventClickBlock){
event.setUseItemInHand(Result.DENY);
@ -86,7 +99,7 @@ public class BlockInteractListener extends CheckListener {
boolean cancelled = false;
final BlockFace face = event.getBlockFace();
final Location loc = player.getLocation();
final Location loc = player.getLocation(useLoc);
// Interaction speed.
if (!cancelled && speed.isEnabled(player) && speed.check(player, data, cc)){
@ -114,5 +127,6 @@ public class BlockInteractListener extends CheckListener {
event.setUseItemInHand(Result.DENY);
event.setCancelled(true);
}
useLoc.setWorld(null);
}
}

View File

@ -9,8 +9,8 @@ import fr.neatmonster.nocheatplus.actions.ParameterName;
import fr.neatmonster.nocheatplus.checks.Check;
import fr.neatmonster.nocheatplus.checks.CheckType;
import fr.neatmonster.nocheatplus.checks.ViolationData;
import fr.neatmonster.nocheatplus.checks.blockbreak.BlockBreakData;
import fr.neatmonster.nocheatplus.checks.blockinteract.BlockInteractData;
import fr.neatmonster.nocheatplus.permissions.Permissions;
import fr.neatmonster.nocheatplus.utilities.BlockProperties;
import fr.neatmonster.nocheatplus.utilities.TickTask;
import fr.neatmonster.nocheatplus.utilities.TrigUtil;
@ -29,8 +29,8 @@ public class Against extends Check {
boolean violation = false;
// TODO: Make more precise (workarounds like WATER_LILY, general points).
// Workaround for signs on cactus and similar.
final int againstId = blockAgainst.getTypeId();
if (againstId == Material.AIR.getId()) {
final Material againstType = blockAgainst.getType();
if (againstType == null || againstType == Material.AIR) {
// Attempt to workaround blocks like cactus.
final BlockInteractData bdata = BlockInteractData.getData(player);
if (bdata.lastType != null && bdata.lastX != Integer.MAX_VALUE && TickTask.getTick() == bdata.lastTick && TrigUtil.manhattan(bdata.lastX, bdata.lastY, bdata.lastZ, blockAgainst) == 0) {
@ -41,19 +41,20 @@ public class Against extends Check {
return false;
}
}
if (BlockProperties.isLiquid(againstId)) {
if ((placedMat != Material.WATER_LILY || !BlockProperties.isLiquid(block.getRelative(BlockFace.DOWN).getTypeId()))) {
if (BlockProperties.isLiquid(againstType)) {
if ((placedMat != Material.WATER_LILY || !BlockProperties.isLiquid(block.getRelative(BlockFace.DOWN).getType())) && !player.hasPermission(Permissions.BLOCKPLACE_AGAINST_LIQUIDS)) {
violation = true;
}
}
else if (againstId == Material.AIR.getId()) {
else if (againstType == Material.AIR && !player.hasPermission(Permissions.BLOCKPLACE_AGAINST_AIR)) {
violation = true;
}
// Handle violation and return.
if (violation) {
data.againstVL += 1.0;
final ViolationData vd = new ViolationData(this, player, data.againstVL, 1, cc.againstActions);
vd.setParameter(ParameterName.BLOCK_ID, Integer.toString(placedMat.getId()));
vd.setParameter(ParameterName.BLOCK_TYPE, placedMat.toString());
vd.setParameter(ParameterName.BLOCK_ID, Integer.toString(BlockProperties.getId(placedMat)));
return executeActions(vd);
} else {
data.againstVL *= 0.99; // Assume one false positive every 100 blocks.

View File

@ -1,8 +1,11 @@
package fr.neatmonster.nocheatplus.checks.blockplace;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import org.bukkit.Material;
import org.bukkit.entity.Player;
import fr.neatmonster.nocheatplus.actions.ActionList;
@ -69,6 +72,7 @@ public class BlockPlaceConfig extends ACheckConfig {
public final ActionList fastPlaceActions;
public final boolean noSwingCheck;
public final Set<Material> noSwingExceptions = new HashSet<Material>();
public final ActionList noSwingActions;
public final boolean reachCheck;
@ -104,6 +108,7 @@ public class BlockPlaceConfig extends ACheckConfig {
fastPlaceActions = data.getOptimizedActionList(ConfPaths.BLOCKPLACE_FASTPLACE_ACTIONS, Permissions.BLOCKPLACE_FASTPLACE);
noSwingCheck = data.getBoolean(ConfPaths.BLOCKPLACE_NOSWING_CHECK);
data.readMaterialFromList(ConfPaths.BLOCKPLACE_NOSWING_EXCEPTIONS, noSwingExceptions);
noSwingActions = data.getOptimizedActionList(ConfPaths.BLOCKPLACE_NOSWING_ACTIONS, Permissions.BLOCKPLACE_NOSWING);
reachCheck = data.getBoolean(ConfPaths.BLOCKPLACE_REACH_CHECK);

View File

@ -75,6 +75,9 @@ public class BlockPlaceListener extends CheckListener {
/** The speed check. */
private final Speed speed = addCheck(new Speed());
/** For temporary use: LocUtil.clone before passing deeply, call setWorld(null) after use. */
private final Location useLoc = new Location(null, 0, 0, 0);
public BlockPlaceListener(){
super(CheckType.BLOCKPLACE);
}
@ -122,7 +125,7 @@ public class BlockPlaceListener extends CheckListener {
}
// No swing check (player doesn't swing their arm when placing a lily pad).
if (!cancelled && placedMat != Material.WATER_LILY && noSwing.isEnabled(player) && noSwing.check(player, data, cc)) {
if (!cancelled && !cc.noSwingExceptions.contains(placedMat) && noSwing.isEnabled(player) && noSwing.check(player, data, cc)) {
// Consider skipping all insta placables or using simplified version (true or true within time frame).
cancelled = true;
}
@ -146,6 +149,8 @@ public class BlockPlaceListener extends CheckListener {
if (cancelled) {
event.setCancelled(cancelled);
}
// Cleanup
// Reminder(currently unused): useLoc.setWorld(null);
}
@EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true)
@ -264,7 +269,7 @@ public class BlockPlaceListener extends CheckListener {
boolean cancel = false;
if (speed.isEnabled(player)){
final long now = System.currentTimeMillis();
final Location loc = player.getLocation();
final Location loc = player.getLocation(useLoc);
if (Combined.checkYawRate(player, loc.getYaw(), now, loc.getWorld().getName())){
// Yawrate (checked extra).
cancel = true;
@ -285,21 +290,22 @@ public class BlockPlaceListener extends CheckListener {
// Do nothing !
// TODO: Might have further flags?
}
else if (!BlockProperties.isPassable(projectile.getLocation())){
else if (!BlockProperties.isPassable(projectile.getLocation(useLoc))){
// Launch into a block.
// TODO: This might be a general check later.
cancel = true;
}
else{
if (!BlockProperties.isPassable(player.getEyeLocation(), projectile.getLocation())){
if (!BlockProperties.isPassable(player.getEyeLocation(), projectile.getLocation(useLoc))){
// (Spare a useLoc2, for this is seldom rather.)
// Something between player
// TODO: This might be a general check later.
cancel = true;
}
else{
final Material mat = player.getLocation().getBlock().getType();
final Material mat = player.getLocation(useLoc).getBlock().getType();
final long flags = BlockProperties.F_CLIMBABLE | BlockProperties.F_LIQUID | BlockProperties.F_IGN_PASSABLE;
if (mat != Material.AIR && (BlockProperties.getBlockFlags(mat.getId()) & flags) == 0 && !mcAccess.hasGravity(mat)){
if (mat != null && mat != Material.AIR && (BlockProperties.getBlockFlags(mat) & flags) == 0 && !mcAccess.hasGravity(mat)){
// Still fails on piston traps etc.
if (!BlockProperties.isPassable(player.getLocation(), projectile.getLocation()) && !BlockProperties.isOnGroundOrResetCond(player, player.getLocation(), MovingConfig.getConfig(player).yOnGround)){
cancel = true;
@ -313,5 +319,7 @@ public class BlockPlaceListener extends CheckListener {
if (cancel){
event.setCancelled(true);
}
// Cleanup.
useLoc.setWorld(null);
}
}

View File

@ -13,6 +13,9 @@ import fr.neatmonster.nocheatplus.utilities.TrigUtil;
* The Direction check will find out if a player tried to interact with something that's not in their field of view.
*/
public class Direction extends Check {
/** For temporary use: LocUtil.clone before passing deeply, call setWorld(null) after use. */
private final Location useLoc = new Location(null, 0, 0, 0);
/**
* Instantiates a new direction check.
@ -38,7 +41,7 @@ public class Direction extends Check {
// How far "off" is the player with their aim. We calculate from the players eye location and view direction to
// the center of the target block. If the line of sight is more too far off, "off" will be bigger than 0.
final Location loc = player.getLocation();
final Location loc = player.getLocation(useLoc);
final Vector direction = loc.getDirection();
double off = TrigUtil.directionCheck(loc, player.getEyeHeight(), direction, against, TrigUtil.DIRECTION_PRECISION);
@ -75,10 +78,11 @@ public class Direction extends Check {
// Execute whatever actions are associated with this check and the violation level and find out if we should
// cancel the event.
cancel = executeActions(player, data.directionVL, distance, cc.directionActions);
} else
} else {
// Player did likely nothing wrong, reduce violation counter to reward them.
data.directionVL *= 0.9D;
}
useLoc.setWorld(null);
return cancel;
}
}

View File

@ -38,14 +38,14 @@ public class FastPlace extends Check {
// Short term arrivals.
final int tick = TickTask.getTick();
if (tick < data.fastPlaceShortTermTick ){
if (tick < data.fastPlaceShortTermTick ) {
// TickTask got reset.
data.fastPlaceShortTermTick = tick;
data.fastPlaceShortTermCount = 1;
}
else if (tick - data.fastPlaceShortTermTick < cc.fastPlaceShortTermTicks){
// Account for server side lag.
if (!cc.lag || TickTask.getLag(50L * (tick - data.fastPlaceShortTermTick), true) < 1.2){
if (!cc.lag || TickTask.getLag(50L * (tick - data.fastPlaceShortTermTick), true) < 1.2f){
// Within range, add.
data.fastPlaceShortTermCount ++;
}
@ -62,9 +62,9 @@ public class FastPlace extends Check {
// Find if one of both or both are violations:
final float fullViolation;
if (fullScore > cc.fastPlaceLimit){
if (fullScore > cc.fastPlaceLimit) {
// Account for server side lag.
if (cc.lag){
if (cc.lag) {
fullViolation = fullScore / TickTask.getLag(data.fastPlaceBuckets.bucketDuration() * data.fastPlaceBuckets.numberOfBuckets(), true) - cc.fastPlaceLimit;
}
else{
@ -78,14 +78,16 @@ public class FastPlace extends Check {
final float violation = Math.max(fullViolation, shortTermViolation);
boolean cancel = false;
if (violation > 0){
final double change = violation / 1000;
if (violation > 0f) {
final double change = (double) violation;
data.fastPlaceVL += change;
cancel = executeActions(player, data.fastPlaceVL, change, cc.fastPlaceActions);
}
else if (data.fastPlaceVL > 0d && fullScore < cc.fastPlaceLimit * .75)
else if (data.fastPlaceVL > 0d && fullScore < cc.fastPlaceLimit * .75) {
data.fastPlaceVL *= 0.95;
}
return cancel;
}
}

View File

@ -3,6 +3,7 @@ package fr.neatmonster.nocheatplus.checks.blockplace;
import java.util.Map;
import org.bukkit.GameMode;
import org.bukkit.Location;
import org.bukkit.block.Block;
import org.bukkit.entity.Player;
@ -22,6 +23,9 @@ public class Reach extends Check {
/** The maximum distance allowed to interact with a block in survival mode. */
public static final double SURVIVAL_DISTANCE = 5.2D;
/** For temporary use: LocUtil.clone before passing deeply, call setWorld(null) after use. */
private final Location useLoc = new Location(null, 0, 0, 0);
/**
* Instantiates a new reach check.
@ -35,6 +39,7 @@ public class Reach extends Check {
*
* @param player
* the player
* @param loc
* @param cc
* @param data2
* @param location
@ -49,7 +54,9 @@ public class Reach extends Check {
// Distance is calculated from eye location to center of targeted block. If the player is further away from their
// target than allowed, the difference will be assigned to "distance".
final double distance = TrigUtil.distance(player.getEyeLocation(), block) - distanceLimit;
final Location eyeLoc = player.getLocation(useLoc);
eyeLoc.setY(eyeLoc.getY() + player.getEyeHeight());
final double distance = TrigUtil.distance(eyeLoc, block) - distanceLimit;
if (distance > 0) {
// They failed, increment violation level.
@ -66,7 +73,9 @@ public class Reach extends Check {
data.reachVL *= 0.9D;
}
// Cleanup.
useLoc.setWorld(null);
return cancel;
}

View File

@ -15,6 +15,7 @@ import fr.neatmonster.nocheatplus.config.ConfPaths;
import fr.neatmonster.nocheatplus.config.ConfigFile;
import fr.neatmonster.nocheatplus.config.ConfigManager;
import fr.neatmonster.nocheatplus.permissions.Permissions;
import fr.neatmonster.nocheatplus.utilities.ColorUtil;
/**
* Configurations specific for the "chat" checks. Every world gets one of these assigned to it, or if a world doesn't
@ -104,7 +105,8 @@ public class ChatConfig extends AsyncCheckConfig {
public final float textMessageNoLetter;
public final float textGlobalWeight;
public final float textPlayerWeight;
public boolean textEngineMaximum;
public final boolean textEngineMaximum;
public final boolean textAllowVLReset;
public final boolean textDebug;
public final boolean chatWarningCheck;
@ -120,6 +122,7 @@ public class ChatConfig extends AsyncCheckConfig {
public final long loginsStartupDelay;
public final boolean consoleOnlyCheck;
public final String consoleOnlyMessage;
public final boolean relogCheck;
@ -192,6 +195,7 @@ public class ChatConfig extends AsyncCheckConfig {
textEngineMaximum = config.getBoolean(ConfPaths.CHAT_TEXT_ENGINE_MAXIMUM, true);
textDebug = config.getBoolean(ConfPaths.CHAT_TEXT_DEBUG, false);
textFreqNormActions = config.getOptimizedActionList(ConfPaths.CHAT_TEXT_FREQ_NORM_ACTIONS, Permissions.CHAT_TEXT);
textAllowVLReset = config.getBoolean(ConfPaths.CHAT_TEXT_ALLOWVLRESET);
chatWarningCheck = config.getBoolean(ConfPaths.CHAT_WARNING_CHECK);
chatWarningLevel = (float) config.getDouble(ConfPaths.CHAT_WARNING_LEVEL);
@ -214,6 +218,7 @@ public class ChatConfig extends AsyncCheckConfig {
relogActions = config.getOptimizedActionList(ConfPaths.CHAT_RELOG_ACTIONS, Permissions.CHAT_RELOG);
consoleOnlyCheck = config.getBoolean(ConfPaths.PROTECT_COMMANDS_CONSOLEONLY_ACTIVE);
consoleOnlyMessage = ColorUtil.replaceColors(config.getString(ConfPaths.PROTECT_COMMANDS_CONSOLEONLY_MSG));
}

View File

@ -1,8 +1,9 @@
package fr.neatmonster.nocheatplus.checks.chat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import org.bukkit.ChatColor;
import org.bukkit.command.Command;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
@ -159,39 +160,46 @@ public class ChatListener extends CheckListener implements INotifyReload, JoinLe
// Trim is necessary because the server accepts leading spaces with commands.
final String message = event.getMessage();
final String lcMessage = message.trim().toLowerCase();
// TODO: Remove bukkit: etc.
final String[] split = lcMessage.split(" ", 2);
final String alias = split[0].substring(1);
final Command command = CommandUtil.getCommand(alias);
final String lcAltMessage;
final List<String> messageVars = new ArrayList<String>(); // Could as well use an array and allow null on input of SimpleCharPrefixTree.
messageVars.add(lcMessage);
String checkMessage = message; // Message to run chat checks on.
if (command != null){
lcAltMessage = "/" + command.getLabel().toLowerCase() + (split.length > 1 ? (" " + split[1]) : "");
messageVars.add("/" + command.getLabel().toLowerCase() + (split.length > 1 ? (" " + split[1]) : ""));
}
else{
lcAltMessage = lcMessage;
}
// Prevent /op and /deop commands from being used by players.
if (cc.consoleOnlyCheck && consoleOnlyCommands.hasAnyPrefixWords(lcMessage, lcAltMessage)) {
if (alias.indexOf(":") != -1) {
final int index = message.indexOf(":") + 1;
if (index < message.length()) {
checkMessage = message.substring(index);
messageVars.add(checkMessage.toLowerCase());
}
}
// Prevent commands from being used by players (e.g. /op /deop /reload).
if (cc.consoleOnlyCheck && consoleOnlyCommands.hasAnyPrefixWords(messageVars)) {
if (command == null || command.testPermission(player)){
player.sendMessage(ChatColor.RED + "I'm sorry, but this command can't be executed in chat. Use the console instead!");
player.sendMessage(cc.consoleOnlyMessage);
}
event.setCancelled(true);
return;
}
// Handle as chat or command.
final boolean handleAsChat = chatCommands.hasAnyPrefixWords(lcMessage, lcAltMessage);
if (handleAsChat){
if (chatCommands.hasAnyPrefixWords(messageVars)){
// Treat as chat.
// TODO: Consider requesting permission updates on these, for consistency.
// TODO: Cut off the command (?).
if (textChecks(player, message, true, false)) {
// TODO: Cut off the command ?.
if (textChecks(player, checkMessage, true, false)) {
event.setCancelled(true);
}
}
else if (!commandExclusions.hasAnyPrefixWords(lcMessage, lcAltMessage)){
else if (!commandExclusions.hasAnyPrefixWords(messageVars)){
// Treat as command.
if (commands.isEnabled(player) && commands.check(player, message, captcha)) {
if (commands.isEnabled(player) && commands.check(player, checkMessage, captcha)) {
event.setCancelled(true);
}
}

View File

@ -70,7 +70,7 @@ public class Text extends AsyncCheck implements INotifyReload{
// Set some things from the global config.
final ConfigFile config = ConfigManager.getConfigFile();
final NoCheatPlusAPI api = NCPAPIProvider.getNoCheatPlusAPI();
if (engine != null){
if (engine != null) {
engine.clear();
api.removeComponent(engine);
}
@ -80,7 +80,7 @@ public class Text extends AsyncCheck implements INotifyReload{
@Override
public void onReload() {
synchronized(engine){
synchronized(engine) {
engine.clear();
}
init();
@ -120,7 +120,7 @@ public class Text extends AsyncCheck implements INotifyReload{
boolean debug = cc.textDebug || cc.debug;
final List<String> debugParts;
if (debug){
if (debug) {
debugParts = new LinkedList<String>();
debugParts.add("[NoCheatPlus][chat.text] Message ("+player.getName()+"/"+message.length()+"): ");
}
@ -143,13 +143,13 @@ public class Text extends AsyncCheck implements INotifyReload{
// Full message processing. ------------
// Upper case.
if (letterCounts.fullCount.upperCase > msgLen / 3){
if (letterCounts.fullCount.upperCase > msgLen / 3) {
final float wUpperCase = 0.6f * letterCounts.fullCount.getUpperCaseRatio();
score += wUpperCase * cc.textMessageUpperCase;
}
// Letters vs. word length.
if (msgLen > 4){
if (msgLen > 4) {
final float fullRep = letterCounts.fullCount.getLetterCountRatio();
// Long messages: very small and very big are bad !
final float wRepetition = (float) msgLen / 15.0f * Math.abs(0.5f - fullRep);
@ -157,7 +157,7 @@ public class Text extends AsyncCheck implements INotifyReload{
// Number of words vs. length of message
final float fnWords = (float) letterCounts.words.length / (float) msgLen;
if (fnWords > 0.75f){ // TODO: balance or configure or remove ?
if (fnWords > 0.75f) { // TODO: balance or configure or remove ?
score += fnWords * cc.textMessagePartition;
}
}
@ -165,40 +165,40 @@ public class Text extends AsyncCheck implements INotifyReload{
final CombinedData cData = CombinedData.getData(player);
final long timeout = 8000; // TODO: maybe set dynamically in data.
// Repetition of last message.
if (cc.textMsgRepeatSelf != 0f && time - data.chatLastTime < timeout){
if (StringUtil.isSimilar(lcMessage, data.chatLastMessage, 0.8f)){
if (cc.textMsgRepeatSelf != 0f && time - data.chatLastTime < timeout) {
if (StringUtil.isSimilar(lcMessage, data.chatLastMessage, 0.8f)) {
final float timeWeight = (float) (timeout - (time - data.chatLastTime)) / (float) timeout;
score += cc.textMsgRepeatSelf * timeWeight;
}
}
// Repetition of last global message.
if (cc.textMsgRepeatGlobal != 0f && time - lastGlobalTime < timeout){
if (StringUtil.isSimilar(lcMessage, lastGlobalMessage, 0.8f)){
if (cc.textMsgRepeatGlobal != 0f && time - lastGlobalTime < timeout) {
if (StringUtil.isSimilar(lcMessage, lastGlobalMessage, 0.8f)) {
final float timeWeight = (float) (timeout - (time - lastGlobalTime)) / (float) timeout;
score += cc.textMsgRepeatGlobal * timeWeight;
}
}
// Repetition of last cancelled message.
if (cc.textMsgRepeatCancel != 0f && time - lastCancelledTime < timeout){
if (StringUtil.isSimilar(lcMessage, lastCancelledMessage, 0.8f)){
if (cc.textMsgRepeatCancel != 0f && time - lastCancelledTime < timeout) {
if (StringUtil.isSimilar(lcMessage, lastCancelledMessage, 0.8f)) {
final float timeWeight = (float) (timeout - (time - lastCancelledTime)) / (float) timeout;
score += cc.textMsgRepeatCancel * timeWeight;
}
}
// Chat quickly after join.
if (cc.textMsgAfterJoin != 0f && time - cData.lastJoinTime < timeout){
if (cc.textMsgAfterJoin != 0f && time - cData.lastJoinTime < timeout) {
final float timeWeight = (float) (timeout - (time - cData.lastJoinTime)) / (float) timeout;
score += cc.textMsgAfterJoin * timeWeight;
}
// Chat without moving.
if (cc.textMsgNoMoving != 0f && time - cData.lastMoveTime > timeout){
if (cc.textMsgNoMoving != 0f && time - cData.lastMoveTime > timeout) {
score += cc.textMsgNoMoving;
}
// Per word checks. -------------------
float wWords = 0.0f;
final float avwLen = (float) msgLen / (float) letterCounts.words.length;
for (final WordLetterCount word: letterCounts.words){
for (final WordLetterCount word: letterCounts.words) {
float wWord = 0.0f;
final int wLen = word.word.length();
// TODO: ? used letters vs. word length.
@ -232,7 +232,7 @@ public class Text extends AsyncCheck implements INotifyReload{
engMap = engine.process(letterCounts, player.getName(), cc, data);
// TODO: more fine grained sync !s
// TODO: different methods (add or max or add+max or something else).
for (final Float res : engMap.values()){
for (final Float res : engMap.values()) {
if (cc.textEngineMaximum) wEngine = Math.max(wEngine, res.floatValue());
else wEngine += res.floatValue();
}
@ -252,40 +252,46 @@ public class Text extends AsyncCheck implements INotifyReload{
final float shortTermAccumulated = cc.textFreqShortTermWeight * data.chatShortTermFrequency.score(cc.textFreqShortTermFactor);
final boolean shortTermViolation = shortTermAccumulated > cc.textFreqShortTermLevel;
if (normalViolation || shortTermViolation){
if (normalViolation || shortTermViolation) {
lastCancelledMessage = lcMessage;
lastCancelledTime = time;
final double added;
if (shortTermViolation) added = (shortTermAccumulated - cc.textFreqShortTermLevel)/ 3.0;
else added = (accumulated - cc.textFreqNormLevel) / 10.0;
data.textVL += added;
if (shortTermViolation) {
added = (shortTermAccumulated - cc.textFreqShortTermLevel)/ 3.0;
} else {
added = (accumulated - cc.textFreqNormLevel) / 10.0;
}
data.textVL += added;
if (captcha.shouldStartCaptcha(cc, data)){
if (captcha.shouldStartCaptcha(cc, data)) {
captcha.sendNewCaptcha(player, cc, data);
cancel = true;
}
else{
if (shortTermViolation){
if (executeActions(player, data.textVL, added, cc.textFreqShortTermActions, isMainThread))
cancel = true;
if (shortTermViolation) {
if (executeActions(player, data.textVL, added, cc.textFreqShortTermActions, isMainThread)) {
cancel = true;
}
}
else if (normalViolation){
if (executeActions(player, data.textVL, added, cc.textFreqNormActions, isMainThread))
cancel = true;
else if (normalViolation) {
if (executeActions(player, data.textVL, added, cc.textFreqNormActions, isMainThread)) {
cancel = true;
}
}
}
}
else if (cc.chatWarningCheck && time - data.chatWarningTime > cc.chatWarningTimeout && (100f * accumulated / cc.textFreqNormLevel > cc.chatWarningLevel || 100f * shortTermAccumulated / cc.textFreqShortTermLevel > cc.chatWarningLevel)){
else if (cc.chatWarningCheck && time - data.chatWarningTime > cc.chatWarningTimeout && (100f * accumulated / cc.textFreqNormLevel > cc.chatWarningLevel || 100f * shortTermAccumulated / cc.textFreqShortTermLevel > cc.chatWarningLevel)) {
NCPAPIProvider.getNoCheatPlusAPI().sendMessageOnTick(player.getName(), ColorUtil.replaceColors(cc.chatWarningMessage));
data.chatWarningTime = time;
}
else {
data.textVL *= 0.95;
if (normalScore < 2.0f * cc.textFreqNormWeight && shortTermScore < 2.0f * cc.textFreqShortTermWeight)
// Reset the VL.
if (cc.textAllowVLReset && normalScore < 2.0f * cc.textFreqNormWeight && shortTermScore < 2.0f * cc.textFreqShortTermWeight) {
// Reset the VL.
// TODO: maybe elaborate on resetting conditions (after some timeout just divide by two or so?).
data.textVL = 0.0;
}
}
if (debug) {

View File

@ -32,9 +32,7 @@ public class Angle extends Check {
* @param worldChanged
* @return true, if successful
*/
public boolean check(final Player player, final boolean worldChanged) {
final FightConfig cc = FightConfig.getConfig(player);
final FightData data = FightData.getData(player);
public boolean check(final Player player, final boolean worldChanged, final FightData data, final FightConfig cc) {
if (worldChanged){
// TODO: clear some data.
@ -44,12 +42,15 @@ public class Angle extends Check {
boolean cancel = false;
// Remove the old locations from the map.
for (final long time : new TreeMap<Long, Location>(data.angleHits).navigableKeySet())
if (System.currentTimeMillis() - time > 1000L)
data.angleHits.remove(time);
for (final long time : new TreeMap<Long, Location>(data.angleHits).navigableKeySet()) {
if (System.currentTimeMillis() - time > 1000L) {
data.angleHits.remove(time);
}
}
// Add the new location to the map.
data.angleHits.put(System.currentTimeMillis(), player.getLocation());
// TODO: Alter method to store something less fat.
data.angleHits.put(System.currentTimeMillis(), player.getLocation()); // This needs to be a copy at present.
// Not enough data to calculate deltas.
if (data.angleHits.size() < 2)

View File

@ -38,14 +38,8 @@ public class Critical extends Check {
* the player
* @return true, if successful
*/
public boolean check(final Player player) {
final FightConfig cc = FightConfig.getConfig(player);
final FightData data = FightData.getData(player);
public boolean check(final Player player, final Location loc, final FightData data, final FightConfig cc) {
boolean cancel = false;
// We'll need the PlayerLocation to know some important stuff.
final Location loc = player.getLocation();
final float mcFallDistance = player.getFallDistance();
final MovingConfig mCc = MovingConfig.getConfig(player);

View File

@ -7,6 +7,7 @@ import org.bukkit.util.Vector;
import fr.neatmonster.nocheatplus.checks.Check;
import fr.neatmonster.nocheatplus.checks.CheckType;
import fr.neatmonster.nocheatplus.checks.moving.LocationTrace.TraceEntry;
import fr.neatmonster.nocheatplus.utilities.TrigUtil;
/**
@ -22,7 +23,7 @@ public class Direction extends Check {
}
/**
* Checks a player.
* "Classic" check.
*
* @param player
* the player
@ -30,16 +31,14 @@ public class Direction extends Check {
* the damaged
* @return true, if successful
*/
public boolean check(final Player player, final Entity damaged) {
final FightConfig cc = FightConfig.getConfig(player);
final FightData data = FightData.getData(player);
boolean cancel = false;
public boolean check(final Player player, final Location loc, final Entity damaged, final Location dLoc, final FightData data, final FightConfig cc) {
boolean cancel = false;
// Safeguard, if entity is complex, this check will fail due to giant and hard to define hitboxes.
// if (damaged instanceof EntityComplex || damaged instanceof EntityComplexPart)
if (mcAccess.isComplexPart(damaged))
return false;
if (mcAccess.isComplexPart(damaged)) {
return false;
}
// Find out how wide the entity is.
final double width = mcAccess.getWidth(damaged);
@ -47,14 +46,11 @@ public class Direction extends Check {
// entity.height is broken and will always be 0, therefore. Calculate height instead based on boundingBox.
final double height = mcAccess.getHeight(damaged);
final Location dLoc = damaged.getLocation();
// TODO: allow any hit on the y axis (might just adapt interface to use foot position + height)!
// How far "off" is the player with their aim. We calculate from the players eye location and view direction to
// the center of the target entity. If the line of sight is more too far off, "off" will be bigger than 0.
final Location loc = player.getLocation();
final Vector direction = player.getEyeLocation().getDirection();
final Vector direction = loc.getDirection();
final double off;
if (cc.directionStrict){
@ -81,10 +77,117 @@ public class Direction extends Check {
// Deal an attack penalty time.
data.attackPenalty.applyPenalty(cc.directionPenalty);
}
} else
// Reward the player by lowering their violation level.
} else {
// Reward the player by lowering their violation level.
data.directionVL *= 0.8D;
}
return cancel;
}
/**
* Data context for iterating over TraceEntry instances.
* @param player
* @param loc
* @param damaged
* @param damagedLoc
* @param data
* @param cc
* @return
*/
public DirectionContext getContext(final Player player, final Location loc, final Entity damaged, final Location damagedLoc, final FightData data, final FightConfig cc) {
final DirectionContext context = new DirectionContext();
context.damagedComplex = mcAccess.isComplexPart(damaged);
// Find out how wide the entity is.
context.damagedWidth = mcAccess.getWidth(damaged);
// entity.height is broken and will always be 0, therefore. Calculate height instead based on boundingBox.
context.damagedHeight = mcAccess.getHeight(damaged);
context.direction = loc.getDirection();
context.lengthDirection = context.direction.length();
return context;
}
/**
* Check if the player fails the direction check, no change of FightData.
* @param player
* @param loc
* @param damaged
* @param dLoc
* @param context
* @param data
* @param cc
* @return
*/
public boolean loopCheck(final Player player, final Location loc, final Entity damaged, final TraceEntry dLoc, final DirectionContext context, final FightData data, final FightConfig cc) {
// Ignore complex entities for the moment.
if (context.damagedComplex) {
// TODO: Revise :p
return false;
}
boolean cancel = false;
// TODO: allow any hit on the y axis (might just adapt interface to use foot position + height)!
// How far "off" is the player with their aim. We calculate from the players eye location and view direction to
// the center of the target entity. If the line of sight is more too far off, "off" will be bigger than 0.
final double off;
if (cc.directionStrict){
off = TrigUtil.combinedDirectionCheck(loc, player.getEyeHeight(), context.direction, dLoc.x, dLoc.y + context.damagedHeight / 2D, dLoc.z, context.damagedWidth, context.damagedHeight, TrigUtil.DIRECTION_PRECISION, 80.0);
}
else{
// Also take into account the angle.
off = TrigUtil.directionCheck(loc, player.getEyeHeight(), context.direction, dLoc.x, dLoc.y + context.damagedHeight / 2D, dLoc.z, context.damagedWidth, context.damagedHeight, TrigUtil.DIRECTION_PRECISION);
}
if (off > 0.1) {
// Player failed the check. Let's try to guess how far they were from looking directly to the entity...
final Vector blockEyes = new Vector(dLoc.x - loc.getX(), dLoc.y + context.damagedHeight / 2D - loc.getY() - player.getEyeHeight(), dLoc.z - loc.getZ());
final double distance = blockEyes.crossProduct(context.direction).length() / context.lengthDirection;
context.minViolation = Math.min(context.minViolation, distance);
}
context.minResult = Math.min(context.minResult, off);
return cancel;
}
/**
* Apply changes to FightData according to check results (context), trigger violations.
* @param player
* @param loc
* @param damaged
* @param context
* @param forceViolation
* @param data
* @param cc
* @return
*/
public boolean loopFinish(final Player player, final Location loc, final Entity damaged, final DirectionContext context, final boolean forceViolation, final FightData data, final FightConfig cc) {
boolean cancel = false;
final double off = forceViolation && context.minViolation != Double.MAX_VALUE ? context.minViolation : context.minResult;
if (off == Double.MAX_VALUE) {
return false;
}
else if (off > 0.1) {
// Add the overall violation level of the check.
data.directionVL += context.minViolation;
// Execute whatever actions are associated with this check and the violation level and find out if we should
// cancel the event.
cancel = executeActions(player, data.directionVL, context.minViolation, cc.directionActions);
if (cancel) {
// Deal an attack penalty time.
data.attackPenalty.applyPenalty(cc.directionPenalty);
}
}
else {
// Reward the player by lowering their violation level.
data.directionVL *= 0.8D;
}
return cancel;
}
}

View File

@ -0,0 +1,23 @@
package fr.neatmonster.nocheatplus.checks.fight;
import org.bukkit.util.Vector;
/**
* Context data for the direction check, for repeated use within a loop.
* @author mc_dev
*
*/
public class DirectionContext {
public boolean damagedComplex;
public double damagedWidth;
public double damagedHeight;
public Vector direction = null;
public double lengthDirection;
/** Minimum value for the distance that was a violation. */
public double minViolation = Double.MAX_VALUE;
/** Minimum value for off. */
public double minResult = Double.MAX_VALUE;
}

View File

@ -32,7 +32,8 @@ public class FastHeal extends Check {
else{
// Violation.
final double correctedDiff = ((double) time - data.fastHealRefTime) * TickTask.getLag(cc.fastHealInterval);
// TODO: Consider using a simple buffer as well (to get closer to the correct interva).
// TODO: Consider using a simple buffer as well (to get closer to the correct interval).
// TODO: Check if we added a buffer.
if (correctedDiff < cc.fastHealInterval){
data.fastHealBuffer -= (cc.fastHealInterval - correctedDiff);
if (data.fastHealBuffer <= 0){

View File

@ -131,7 +131,7 @@ public class FightData extends ACheckData {
// Shared
public String lastWorld = "";
public int lastAttackTick = 0;
public double lastAttackedX = Integer.MAX_VALUE;
public double lastAttackedX = Double.MAX_VALUE;
public double lastAttackedY;
public double lastAttackedZ;
@ -197,4 +197,12 @@ public class FightData extends ACheckData {
// Start with full fast-heal buffer.
fastHealBuffer = cc.fastHealBuffer;
}
public void onWorldChange() {
angleHits.clear();
lastAttackedX = Double.MAX_VALUE;
lastAttackTick = 0;
lastWorld = "";
}
}

View File

@ -1,5 +1,7 @@
package fr.neatmonster.nocheatplus.checks.fight;
import java.util.Iterator;
import org.bukkit.Location;
import org.bukkit.enchantments.Enchantment;
import org.bukkit.entity.Entity;
@ -25,6 +27,8 @@ import fr.neatmonster.nocheatplus.checks.CheckType;
import fr.neatmonster.nocheatplus.checks.combined.Combined;
import fr.neatmonster.nocheatplus.checks.combined.Improbable;
import fr.neatmonster.nocheatplus.checks.inventory.Items;
import fr.neatmonster.nocheatplus.checks.moving.LocationTrace;
import fr.neatmonster.nocheatplus.checks.moving.LocationTrace.TraceEntry;
import fr.neatmonster.nocheatplus.checks.moving.MediumLiftOff;
import fr.neatmonster.nocheatplus.checks.moving.MovingConfig;
import fr.neatmonster.nocheatplus.checks.moving.MovingData;
@ -74,6 +78,12 @@ public class FightListener extends CheckListener implements JoinLeaveListener{
/** The speed check. */
private final Speed speed = addCheck(new Speed());
/** For temporary use: LocUtil.clone before passing deeply, call setWorld(null) after use. */
private final Location useLoc1 = new Location(null, 0, 0, 0);
/** For temporary use: LocUtil.clone before passing deeply, call setWorld(null) after use. */
private final Location useLoc2 = new Location(null, 0, 0, 0);
public FightListener(){
super(CheckType.FIGHT);
}
@ -100,15 +110,21 @@ public class FightListener extends CheckListener implements JoinLeaveListener{
final long now = System.currentTimeMillis();
final boolean worldChanged = !worldName.equals(data.lastWorld);
final Location loc = player.getLocation();
final Location targetLoc = damaged.getLocation();
final Location loc = player.getLocation(useLoc1);
// // Bad pitch/yaw, just in case.
// if (LocUtil.needsDirectionCorrection(useLoc1.getYaw(), useLoc1.getPitch())) {
// mcAccess.correctDirection(player);
// player.getLocation(useLoc1);
// }
final Location damagedLoc = damaged.getLocation(useLoc2);
// final double targetDist = CheckUtils.distance(loc, targetLoc); // TODO: Calculate distance as is done in fight.reach !
final double targetMove;
final int tickAge;
final long msAge; // Milliseconds the ticks actually took.
final double normalizedMove; // Blocks per second.
// TODO: relative distance (player - target)!
if (data.lastAttackedX == Integer.MAX_VALUE || tick < data.lastAttackTick || worldChanged || tick - data.lastAttackTick > 20){
// TODO: Use trace for this ?
if (data.lastAttackedX == Double.MAX_VALUE || tick < data.lastAttackTick || worldChanged || tick - data.lastAttackTick > 20){
// TODO: 20 ?
tickAge = 0;
targetMove = 0.0;
@ -118,7 +134,7 @@ public class FightListener extends CheckListener implements JoinLeaveListener{
else{
tickAge = tick - data.lastAttackTick;
// TODO: Maybe use 3d distance if dy(normalized) is too big.
targetMove = TrigUtil.distance(data.lastAttackedX, data.lastAttackedZ, targetLoc.getX(), targetLoc.getZ());
targetMove = TrigUtil.distance(data.lastAttackedX, data.lastAttackedZ, damagedLoc.getX(), damagedLoc.getZ());
msAge = (long) (50f * TickTask.getLag(50L * tickAge) * (float) tickAge);
normalizedMove = msAge == 0 ? targetMove : targetMove * Math.min(20.0, 1000.0 / (double) msAge);
}
@ -126,15 +142,34 @@ public class FightListener extends CheckListener implements JoinLeaveListener{
// TODO: dist < width => skip some checks (direction, ..)
// Check for self hit exploits (mind that projectiles should be excluded)
final LocationTrace damagedTrace;
final Player damagedPlayer;
if (damaged instanceof Player){
final Player damagedPlayer = (Player) damaged;
damagedPlayer = (Player) damaged;
// // Bad pitch/yaw, just in case.
// if (LocUtil.needsDirectionCorrection(useLoc2.getYaw(), useLoc2.getPitch())) {
// mcAccess.correctDirection(damagedPlayer);
// damagedPlayer.getLocation(useLoc2);
// }
// Log.
if (cc.debug && damagedPlayer.hasPermission(Permissions.ADMINISTRATION_DEBUG)){
damagedPlayer.sendMessage("Attacked by " + player.getName() + ": inv=" + mcAccess.getInvulnerableTicks(damagedPlayer) + " ndt=" + damagedPlayer.getNoDamageTicks());
}
// Check for self hit exploits (mind that projectiles are excluded from this.)
if (selfHit.isEnabled(player) && selfHit.check(player, damagedPlayer, data, cc)) {
cancelled = true;
}
// Get+update the damaged players.
// TODO: Problem with NPCs: data stays (not a big problem).
// (This is done even if the event has already been cancelled, to keep track, if the player is on a horse.)
damagedTrace = MovingData.getData(damagedPlayer).updateTrace(damagedPlayer, damagedLoc, tick);
} else {
damagedPlayer = null; // TODO: This is a temporary workaround.
// Use a fake trace.
// TODO: Provide for entities too? E.g. one per player, or a fully fledged bookkeeping thing (EntityData).
//final MovingConfig mcc = MovingConfig.getConfig(damagedLoc.getWorld().getName());
damagedTrace = null; //new LocationTrace(mcc.traceSize, mcc.traceMergeDist);
//damagedTrace.addEntry(tick, damagedLoc.getX(), damagedLoc.getY(), damagedLoc.getZ());
}
if (cc.cancelDead){
@ -176,51 +211,131 @@ public class FightListener extends CheckListener implements JoinLeaveListener{
}
}
if (angle.isEnabled(player)) {
if (!cancelled && critical.isEnabled(player) && critical.check(player, loc, data, cc)) {
cancelled = true;
}
if (!cancelled && knockback.isEnabled(player) && knockback.check(player, data, cc)) {
cancelled = true;
}
if (!cancelled && noSwing.isEnabled(player) && noSwing.check(player, data, cc)) {
cancelled = true;
}
if (!cancelled && player.isBlocking() && !player.hasPermission(Permissions.MOVING_SURVIVALFLY_BLOCKING)) {
cancelled = true;
}
// TODO: Order of all these checks ...
// Checks that use LocationTrace.
// TODO: Later optimize (...), should reverse check window ?
// First loop through reach and direction, to determine a window.
final boolean reachEnabled = !cancelled && reach.isEnabled(player);
final boolean directionEnabled = !cancelled && direction.isEnabled(player);
if (reachEnabled || directionEnabled) {
if (damagedPlayer != null) {
// TODO: Move to a method (trigonometric checks).
final ReachContext reachContext = reachEnabled ? reach.getContext(player, loc, damaged, damagedLoc, data, cc) : null;
final DirectionContext directionContext = directionEnabled ? direction.getContext(player, loc, damaged, damagedLoc, data, cc) : null;
final long traceOldest = tick; // - damagedTrace.getMaxSize(); // TODO: Set by window.
// TODO: Iterating direction: could also start from latest, be it on occasion.
Iterator<TraceEntry> traceIt = damagedTrace.maxAgeIterator(traceOldest);
boolean violation = true; // No tick with all checks passed.
boolean reachPassed = !reachEnabled; // Passed individually for some tick.
boolean directionPassed = !directionEnabled; // Passed individually for some tick.
// TODO: Maintain a latency estimate + max diff and invalidate completely (i.e. iterate from latest NEXT time)], or just max latency.
while (traceIt.hasNext()) {
final TraceEntry entry = traceIt.next();
// Simplistic just check both until end or hit.
// TODO: Other default distances/tolerances.
boolean thisPassed = true;
if (reachEnabled) {
if (reach.loopCheck(player, loc, damagedPlayer, entry, reachContext, data, cc)) {
thisPassed = false;
} else {
reachPassed = true;
}
}
// TODO: For efficiency one could omit checking at all if reach is failed all the time.
if (directionEnabled && (reachPassed || !directionPassed)) {
if (direction.loopCheck(player, damagedLoc, damagedPlayer, entry, directionContext, data, cc)) {
thisPassed = false;
} else {
directionPassed = true;
}
}
if (thisPassed) {
// TODO: Log/set estimated latency.
violation = false;
break;
}
}
// TODO: How to treat mixed state: violation && reachPassed && directionPassed [current: use min violation // thinkable: silent cancel, if actions have cancel (!)]
// TODO: Adapt according to strictness settings?
if (reachEnabled) {
// TODO: Might ignore if already cancelled by mixed/silent cancel.
if (reach.loopFinish(player, loc, damagedPlayer, reachContext, violation, data, cc)) {
cancelled = true;
}
}
if (directionEnabled) {
// TODO: Might ignore if already cancelled.
if (direction.loopFinish(player, loc, damagedPlayer, directionContext, violation, data, cc)) {
cancelled = true;
}
}
// TODO: Log exact state, probably record min/max latency (individually).
} else {
// Still use the classic methods for non-players. maybe[]
if (reachEnabled && reach.check(player, loc, damaged, damagedLoc, data, cc)) {
cancelled = true;
}
if (directionEnabled && direction.check(player, loc, damaged, damagedLoc, data, cc)) {
cancelled = true;
}
}
}
// Check angle with allowed window.
if (angle.isEnabled(player)) {
// TODO: Revise, use own trace.
// The "fast turning" checks are checked in any case because they accumulate data.
// Improbable yaw changing.
// Improbable yaw changing: Moving events might be missing up to a ten degrees change.
if (Combined.checkYawRate(player, loc.getYaw(), now, worldName, cc.yawRateCheck)) {
// (Check or just feed).
// TODO: Work into this somehow attacking the same aim and/or similar aim position (not cancel then).
cancelled = true;
}
// Angle check.
if (angle.check(player, worldChanged)) cancelled = true;
if (angle.check(player, worldChanged, data, cc)) {
if (!cancelled && cc.debug) {
System.out.println(player.getName() + " fight.angle cancel without yawrate cancel.");
}
cancelled = true;
}
}
if (!cancelled && critical.isEnabled(player) && critical.check(player))
cancelled = true;
if (!cancelled && knockback.isEnabled(player) && knockback.check(player))
cancelled = true;
if (!cancelled && noSwing.isEnabled(player) && noSwing.check(player))
cancelled = true;
if (!cancelled && player.isBlocking() && !player.hasPermission(Permissions.MOVING_SURVIVALFLY_BLOCKING))
cancelled = true;
// TODO: Order of the last two [might put first] ?
if (!cancelled && reach.isEnabled(player) && reach.check(player, damaged))
cancelled = true;
if (!cancelled && direction.isEnabled(player) && direction.check(player, damaged))
cancelled = true;
// Set values.
data.lastWorld = worldName;
data.lastAttackTick = tick;
data.lastAttackedX = targetLoc.getX();
data.lastAttackedY = targetLoc.getY();
data.lastAttackedZ = targetLoc.getZ();
data.lastAttackedX = damagedLoc.getX();
data.lastAttackedY = damagedLoc.getY();
data.lastAttackedZ = damagedLoc.getZ();
// data.lastAttackedDist = targetDist;
// Care for the "lost sprint problem": sprint resets, client moves as if still...
// TODO: Use stored distance calculation same as reach check?
// TODO: For pvp: make use of "player was there" heuristic later on.
// TODO: Confine further with simple pre-conditions.
if (!cancelled && TrigUtil.distance(loc.getX(), loc.getZ(), targetLoc.getX(), targetLoc.getZ()) < 4.5){
// TODO: Evaluate if moving traces can help here.
if (!cancelled && TrigUtil.distance(loc.getX(), loc.getZ(), damagedLoc.getX(), damagedLoc.getZ()) < 4.5){
final MovingData mData = MovingData.getData(player);
// Check if fly checks is an issue at all, re-check "real sprinting".
if (mData.fromX != Double.MAX_VALUE && mData.mediumLiftOff != MediumLiftOff.LIMIT_JUMP){
@ -233,7 +348,7 @@ public class FightListener extends CheckListener implements JoinLeaveListener{
// TODO: What would mData.lostSprintCount > 0 mean here?
mData.lostSprintCount = 7;
if ((cc.debug || mc.debug) && BuildParameters.debugLevel > 0){
System.out.println(player.getName() + " (lostsprint) hDist to last from: " + hDist + " | targetdist=" + TrigUtil.distance(loc.getX(), loc.getZ(), targetLoc.getX(), targetLoc.getZ()) + " | sprinting=" + player.isSprinting() + " | food=" + player.getFoodLevel() +" | hbuf=" + mData.sfHorizontalBuffer);
System.out.println(player.getName() + " (lostsprint) hDist to last from: " + hDist + " | targetdist=" + TrigUtil.distance(loc.getX(), loc.getZ(), damagedLoc.getX(), damagedLoc.getZ()) + " | sprinting=" + player.isSprinting() + " | food=" + player.getFoodLevel() +" | hbuf=" + mData.sfHorizontalBuffer);
}
}
}
@ -248,7 +363,11 @@ public class FightListener extends CheckListener implements JoinLeaveListener{
System.out.println(player.getName() + " ~ attack penalty.");
}
}
// Cleanup.
useLoc1.setWorld(null);
useLoc2.setWorld(null);
return cancelled;
}
@ -374,7 +493,9 @@ public class FightListener extends CheckListener implements JoinLeaveListener{
final Entity entity = event.getEntity();
if (entity instanceof Player){
final Player player = (Player) entity;
if (godMode.isEnabled(player)) godMode.death(player);
if (godMode.isEnabled(player)) {
godMode.death(player);
}
}
}
@ -408,6 +529,11 @@ public class FightListener extends CheckListener implements JoinLeaveListener{
final Entity entity = event.getEntity();
if (!(entity instanceof Player)) return;
final Player player = (Player) entity;
if (player.isDead() && BridgeHealth.getHealth(player) <= 0.0) {
// Heal after death.
event.setCancelled(true);
return;
}
if (event.getRegainReason() != RegainReason.SATIATED) {
return;
}
@ -444,8 +570,7 @@ public class FightListener extends CheckListener implements JoinLeaveListener{
@EventHandler(priority = EventPriority.MONITOR)
public void onPlayerChangedWorld(final PlayerChangedWorldEvent event){
final FightData data = FightData.getData(event.getPlayer());
data.angleHits.clear();
FightData.getData(event.getPlayer()).onWorldChange();
}
@EventHandler(ignoreCancelled = false, priority = EventPriority.MONITOR)

View File

@ -173,7 +173,7 @@ public class GodMode extends Check {
public void death(final Player player) {
// TODO: Is this still relevant ?
// First check if the player is really dead (e.g. another plugin could have just fired an artificial event).
if (BridgeHealth.getHealth(player) <= 0.0 && player.isDead()){
if (BridgeHealth.getHealth(player) <= 0.0 && player.isDead()) {
try {
// Schedule a task to be executed in roughly 1.5 seconds.
// TODO: Get plugin otherwise !?

View File

@ -26,10 +26,7 @@ public class Knockback extends Check {
* the player
* @return true, if successful
*/
public boolean check(final Player player) {
final FightConfig cc = FightConfig.getConfig(player);
final FightData data = FightData.getData(player);
public boolean check(final Player player, final FightData data, final FightConfig cc) {
boolean cancel = false;
final long time = System.currentTimeMillis();

View File

@ -24,9 +24,7 @@ public class NoSwing extends Check {
* the player
* @return true, if successful
*/
public boolean check(final Player player) {
final FightData data = FightData.getData(player);
public boolean check(final Player player, final FightData data, final FightConfig cc) {
boolean cancel = false;
// Did they swing his arm before?
@ -40,9 +38,10 @@ public class NoSwing extends Check {
// Execute whatever actions are associated with this check and the violation level and find out if we should
// cancel the event.
cancel = executeActions(player, data.noSwingVL, 1D, FightConfig.getConfig(player).noSwingActions);
cancel = executeActions(player, data.noSwingVL, 1D, cc.noSwingActions);
}
return cancel;
}
}

View File

@ -12,9 +12,11 @@ import org.bukkit.util.Vector;
import fr.neatmonster.nocheatplus.checks.Check;
import fr.neatmonster.nocheatplus.checks.CheckType;
import fr.neatmonster.nocheatplus.checks.combined.Improbable;
import fr.neatmonster.nocheatplus.checks.moving.LocationTrace.TraceEntry;
import fr.neatmonster.nocheatplus.permissions.Permissions;
import fr.neatmonster.nocheatplus.utilities.StringUtil;
import fr.neatmonster.nocheatplus.utilities.TickTask;
import fr.neatmonster.nocheatplus.utilities.TrigUtil;
/**
* The Reach check will find out if a player interacts with something that's too far away.
@ -43,7 +45,7 @@ public class Reach extends Check {
}
/**
* Checks a player.
* "Classic" check.
*
* @param player
* the player
@ -51,10 +53,7 @@ public class Reach extends Check {
* the damaged
* @return true, if successful
*/
public boolean check(final Player player, final Entity damaged) {
final FightConfig cc = FightConfig.getConfig(player);
final FightData data = FightData.getData(player);
public boolean check(final Player player, final Location pLoc, final Entity damaged, final Location dRef, final FightData data, final FightConfig cc) {
boolean cancel = false;
// The maximum distance allowed to interact with an entity in survival mode.
@ -67,20 +66,17 @@ public class Reach extends Check {
final double distanceLimit = player.getGameMode() == GameMode.CREATIVE ? CREATIVE_DISTANCE : SURVIVAL_DISTANCE + getDistMod(damaged);
final double distanceMin = (distanceLimit - DYNAMIC_RANGE) / distanceLimit;
// Reference locations to check distance for.
final Location dRef = damaged.getLocation();
final double height = mcAccess.getHeight(damaged);
final Location pRef = player.getEyeLocation();
// Refine y position.
// TODO: Make a little more accurate by counting in the actual bounding box.
final double pY = pRef.getY();
final double pY = pLoc.getY() + player.getEyeHeight();
final double dY = dRef.getY();
if (pY <= dY); // Keep the foot level y.
else if (pY >= dY + height) dRef.setY(dY + height); // Highest ref y.
else dRef.setY(pY); // Level with damaged.
final Vector pRel = dRef.toVector().subtract(pRef.toVector());
final Vector pRel = dRef.toVector().subtract(pLoc.toVector().setY(pY)); // TODO: Run calculations on numbers only :p.
// Distance is calculated from eye location to center of targeted. If the player is further away from their target
// than allowed, the difference will be assigned to "distance".
@ -138,4 +134,139 @@ public class Reach extends Check {
return cancel;
}
/**
* Data context for iterating over TraceEntry instances.
* @param player
* @param pLoc
* @param damaged
* @param damagedLoc
* @param data
* @param cc
* @return
*/
public ReachContext getContext(final Player player, final Location pLoc, final Entity damaged, final Location damagedLoc, final FightData data, final FightConfig cc) {
final ReachContext context = new ReachContext();
context.distanceLimit = player.getGameMode() == GameMode.CREATIVE ? CREATIVE_DISTANCE : cc.reachSurvivalDistance + getDistMod(damaged);
context.distanceMin = (context.distanceLimit - cc.reachReduceDistance) / context.distanceLimit;
context.damagedHeight = mcAccess.getHeight(damaged);
//context.eyeHeight = player.getEyeHeight();
context.pY = pLoc.getY() + player.getEyeHeight();
return context;
}
/**
* Check if the player fails the reach check, no change of FightData.
* @param player
* @param pLoc
* @param damaged
* @param dRef
* @param context
* @param data
* @param cc
* @return
*/
public boolean loopCheck(final Player player, final Location pLoc, final Entity damaged, final TraceEntry dRef, final ReachContext context, final FightData data, final FightConfig cc) {
boolean cancel = false;
// Refine y position.
final double dY = dRef.y;
double y = dRef.y;
if (context.pY <= dY) {
// Keep the foot level y.
}
else if (context.pY >= dY + context.damagedHeight) {
y = dY + context.damagedHeight; // Highest ref y.
}
else {
y = context.pY; // Level with damaged.
}
// Distance is calculated from eye location to center of targeted. If the player is further away from their target
// than allowed, the difference will be assigned to "distance".
// TODO: Run check on squared distances (quite easy to change to stored boundary-sq values).
final double lenpRel = TrigUtil.distance(dRef.x, y, dRef.z, pLoc.getX(), context.pY, pLoc.getZ());
double violation = lenpRel - context.distanceLimit;
if (violation > 0 || lenpRel - context.distanceLimit * data.reachMod > 0){
// TODO: The silent cancel parts should be sen as "no violation" ?
// Set minimum violation in context
context.minViolation = Math.min(context.minViolation, lenpRel);
cancel = true;
}
context.minResult = Math.min(context.minResult, lenpRel);
return cancel;
}
/**
* Apply changes to FightData according to check results (context), trigger violations.
* @param player
* @param pLoc
* @param damaged
* @param context
* @param forceViolation
* @param data
* @param cc
* @return
*/
public boolean loopFinish(final Player player, final Location pLoc, final Entity damaged, final ReachContext context, final boolean forceViolation, final FightData data, final FightConfig cc) {
final double lenpRel = forceViolation && context.minViolation != Double.MAX_VALUE ? context.minViolation : context.minResult;
if (lenpRel == Double.MAX_VALUE) {
return false;
}
double violation = lenpRel - context.distanceLimit;
boolean cancel = false;
if (violation > 0) {
// They failed, increment violation level. This is influenced by lag, so don't do it if there was lag.
if (TickTask.getLag(1000) < 1.5f){
// TODO: 1.5 is a fantasy value.
data.reachVL += violation;
}
// Execute whatever actions are associated with this check and the violation level and find out if we should
// cancel the event.
cancel = executeActions(player, data.reachVL, violation, cc.reachActions);
if (Improbable.check(player, (float) violation / 2f, System.currentTimeMillis(), "fight.reach")){
cancel = true;
}
if (cancel && cc.reachPenalty > 0){
// Apply an attack penalty time.
data.attackPenalty.applyPenalty(cc.reachPenalty);
}
}
else if (lenpRel - context.distanceLimit * data.reachMod > 0){
// Silent cancel.
if (cc.reachPenalty > 0) {
data.attackPenalty.applyPenalty(cc.reachPenalty / 2);
}
cancel = true;
Improbable.feed(player, (float) (lenpRel - context.distanceLimit * data.reachMod) / 4f, System.currentTimeMillis());
}
else{
// Player passed the check, reward them.
data.reachVL *= 0.8D;
}
// Adaption amount for dynamic range.
final double DYNAMIC_STEP = cc.reachReduceStep / cc.reachSurvivalDistance;
if (!cc.reachReduce){
data.reachMod = 1d;
}
else if (lenpRel > context.distanceLimit - cc.reachReduceDistance){
data.reachMod = Math.max(context.distanceMin, data.reachMod - DYNAMIC_STEP);
}
else{
data.reachMod = Math.min(1.0, data.reachMod + DYNAMIC_STEP);
}
if (cc.debug && player.hasPermission(Permissions.ADMINISTRATION_DEBUG)){
player.sendMessage("NC+: Attack/reach " + damaged.getType()+ " height="+ StringUtil.fdec3.format(context.damagedHeight) + " dist=" + StringUtil.fdec3.format(lenpRel) +" @" + StringUtil.fdec3.format(data.reachMod));
}
return cancel;
}
}

View File

@ -0,0 +1,22 @@
package fr.neatmonster.nocheatplus.checks.fight;
/**
* Context data for the reach check, for repeated use within a loop.
* @author mc_dev
*
*/
public class ReachContext {
public double distanceLimit;
public double distanceMin;
public double damagedHeight;
/** Attacking player. */
public double eyeHeight;
/** Eye location y of the attacking player. */
public double pY;
/** Minimum value of lenpRel that was a violation. */
public double minViolation = Double.MAX_VALUE;
/** Minimum value of lenpRel. */
public double minResult = Double.MAX_VALUE;
}

View File

@ -42,20 +42,30 @@ public class InstantBow extends Check {
final long expectedPullDuration = (long) (maxTime - maxTime * (1f - force) * (1f - force)) - cc.instantBowDelay;
// Time taken to pull the string.
final long pullDuration = now - (cc.instantBowStrict ? data.instantBowInteract : data.instantBowShoot);
final long pullDuration;
final boolean valid;
if (cc.instantBowStrict) {
// The interact time is invalid, if set to 0.
valid = data.instantBowInteract != 0;
pullDuration = valid ? (now - data.instantBowInteract) : 0L;
} else {
valid = true;
pullDuration = now - data.instantBowShoot;
}
if ((!cc.instantBowStrict || data.instantBowInteract > 0) && pullDuration >= expectedPullDuration){
if (valid && (!cc.instantBowStrict || data.instantBowInteract > 0L) && pullDuration >= expectedPullDuration) {
// The player was slow enough, reward them by lowering their violation level.
data.instantBowVL *= 0.9D;
}
else if (data.instantBowInteract > now){
else if (valid && data.instantBowInteract > now) {
// Security check if time ran backwards.
// TODO: Maybe this can be removed, though TickTask does not reset at the exact moment.
}
else {
// Account for server side lag.
final long correctedPullduration = cc.lag ? (long) (TickTask.getLag(expectedPullDuration, true) * pullDuration) : pullDuration;
if (correctedPullduration < expectedPullDuration){
// (Do not apply correction to invalid pulling.)
final long correctedPullduration = valid ? (cc.lag ? (long) (TickTask.getLag(expectedPullDuration, true) * pullDuration) : pullDuration) : 0;
if (correctedPullduration < expectedPullDuration) {
// TODO: Consider: Allow one time but set yawrate penalty time ?
final double difference = (expectedPullDuration - pullDuration) / 100D;
@ -68,7 +78,7 @@ public class InstantBow extends Check {
}
}
if (cc.debug && player.hasPermission(Permissions.ADMINISTRATION_DEBUG)){
if (cc.debug && player.hasPermission(Permissions.ADMINISTRATION_DEBUG)) {
player.sendMessage(ChatColor.YELLOW + "NCP: " + ChatColor.GRAY + "Bow shot - force: " + force +", " + (cc.instantBowStrict || pullDuration < 2 * expectedPullDuration ? ("pull time: " + pullDuration) : "") + "(" + expectedPullDuration +")");
}

View File

@ -5,6 +5,7 @@ import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import org.bukkit.Material;
import org.bukkit.entity.Player;
import fr.neatmonster.nocheatplus.actions.ActionList;
@ -71,7 +72,7 @@ public class InventoryConfig extends ACheckConfig {
public final boolean fastConsumeCheck;
public final long fastConsumeDuration;
public final boolean fastConsumeWhitelist;
public final Set<Integer> fastConsumeItems = new HashSet<Integer>();
public final Set<Material> fastConsumeItems = new HashSet<Material>();
public final ActionList fastConsumeActions;
public final boolean instantBowCheck;

View File

@ -79,7 +79,8 @@ public class InventoryData extends ACheckData {
public int fastClickLastCursorAmount = 0;
// Data of the instant bow check.
public long instantBowInteract;
/** Last time right click interact on bow. A value of 0 means 'invalid'.*/
public long instantBowInteract = 0;
public long instantBowShoot;
// Data of the instant eat check.

View File

@ -29,6 +29,7 @@ import fr.neatmonster.nocheatplus.checks.CheckListener;
import fr.neatmonster.nocheatplus.checks.CheckType;
import fr.neatmonster.nocheatplus.checks.combined.Combined;
import fr.neatmonster.nocheatplus.checks.combined.Improbable;
import fr.neatmonster.nocheatplus.compat.BridgeHealth;
import fr.neatmonster.nocheatplus.components.JoinLeaveListener;
import fr.neatmonster.nocheatplus.utilities.InventoryUtil;
@ -55,6 +56,9 @@ public class InventoryListener extends CheckListener implements JoinLeaveListen
private final Open open = addCheck(new Open());
/** For temporary use: LocUtil.clone before passing deeply, call setWorld(null) after use. */
private final Location useLoc = new Location(null, 0, 0, 0);
public InventoryListener(){
super(CheckType.INVENTORY);
}
@ -73,7 +77,7 @@ public class InventoryListener extends CheckListener implements JoinLeaveListen
final Player player = (Player) event.getEntity();
if (instantBow.isEnabled(player)){
final long now = System.currentTimeMillis();
final Location loc = player.getLocation();
final Location loc = player.getLocation(useLoc);
if (Combined.checkYawRate(player, loc.getYaw(), now, loc.getWorld().getName())){
// No else if with this, could be cancelled due to other checks feeding, does not have actions.
event.setCancelled(true);
@ -87,6 +91,7 @@ public class InventoryListener extends CheckListener implements JoinLeaveListen
// Combined fighting speed (Else if: Matter of taste, preventing extreme cascading and actions spam).
event.setCancelled(true);
}
useLoc.setWorld(null);
}
}
}
@ -107,6 +112,10 @@ public class InventoryListener extends CheckListener implements JoinLeaveListen
if (instantEat.isEnabled(player) && instantEat.check(player, event.getFoodLevel())){
event.setCancelled(true);
}
else if (player.isDead() && BridgeHealth.getHealth(player) <= 0.0) {
// Eat after death.
event.setCancelled(true);
}
}
}
@ -219,6 +228,7 @@ public class InventoryListener extends CheckListener implements JoinLeaveListen
if (event.hasItem()){
final ItemStack item = event.getItem();
final Material type = item.getType();
// TODO: Get Magic values (800) from the config.
if (type == Material.BOW){
final long now = System.currentTimeMillis();
// It was a bow, the player starts to pull the string, remember this time.
@ -233,9 +243,13 @@ public class InventoryListener extends CheckListener implements JoinLeaveListen
} else resetAll = true;
// Illegal enchantments hotfix check.
if (Items.checkIllegalEnchantments(player, item)) event.setCancelled(true);
if (Items.checkIllegalEnchantments(player, item)) {
event.setCancelled(true);
}
}
else {
resetAll = true;
}
else resetAll = true;
if (resetAll){
// Nothing that we are interested in, reset data.
@ -248,9 +262,16 @@ public class InventoryListener extends CheckListener implements JoinLeaveListen
@EventHandler(ignoreCancelled = false, priority = EventPriority.LOWEST)
public final void onPlayerInteractEntity(final PlayerInteractEntityEvent event) {
final Player player = event.getPlayer();
if (player.getGameMode() == GameMode.CREATIVE) return;
if (player.getGameMode() == GameMode.CREATIVE) {
return;
}
if (player.isDead() && BridgeHealth.getHealth(player) <= 0.0) {
// No zombies.
event.setCancelled(true);
return;
}
final ItemStack stack = player.getItemInHand();
if (stack != null && stack.getTypeId() == Material.MONSTER_EGG.getId() && items.isEnabled(player)){
if (stack != null && stack.getType() == Material.MONSTER_EGG && items.isEnabled(player)){
event.setCancelled(true);
}
}

View File

@ -1,36 +1,45 @@
package fr.neatmonster.nocheatplus.checks.moving;
import org.bukkit.Location;
import org.bukkit.World;
import fr.neatmonster.nocheatplus.utilities.PlayerLocation;
/**
* Auxiliary methods for Location handling, mainly intended for use with set-back locations.
* @author mc_dev
*
*/
public class LocUtil {
/**
* Simple get a copy (not actually using cloning).
* Get a copy of a location (not actually using cloning).
* @param loc
* @return
* @return A new Location instance.
* @throws NullPointerException if World is null.
*/
public static final Location clone(final Location loc){
return new Location(loc.getWorld(), loc.getX(), loc.getY(), loc.getZ(), loc.getYaw(), loc.getPitch());
return new Location(testWorld(loc.getWorld()), loc.getX(), loc.getY(), loc.getZ(), loc.getYaw(), loc.getPitch());
}
/**
* Clone with given yaw and pitch.
* Get a copy of a location (not actually using cloning), override yaw and pitch with given values.
* @param loc
* @param yaw
* @param pitch
* @return
* @return A new Location instance.
* @throws NullPointerException if the resulting world is null.
*/
public static final Location clone(final Location loc, final float yaw, final float pitch){
return new Location(loc.getWorld(), loc.getX(), loc.getY(), loc.getZ(), yaw, pitch);
return new Location(testWorld(loc.getWorld()), loc.getX(), loc.getY(), loc.getZ(), yaw, pitch);
}
/**
* Clone with yaw and pitch of ref, use ref if setBack is null.
* @param setBack
* @param ref
* @return
* Clone setBack, with yaw and pitch taken from ref, if setBack is null, ref is cloned fully.
* @param setBack Can be null.
* @param ref Must not be null.
* @return A new Location instance.
* @throws NullPointerException if the resulting world is null.
*/
public static final Location clone(final Location setBack, final Location ref) {
if (setBack == null){
@ -49,26 +58,121 @@ public class LocUtil {
}
/**
* SA
* Update setBack by loc.
* @param setBack
* @param loc
* @throws NullPointerException if loc.getWorld() is null.
*/
public static final void set(final Location setBack, final Location loc) {
setBack.setWorld(loc.getWorld());
setBack.setWorld(testWorld(loc.getWorld()));
setBack.setX(loc.getX());
setBack.setY(loc.getY());
setBack.setZ(loc.getZ());
setBack.setYaw(loc.getYaw());
setBack.setPitch(loc.getPitch());
}
/**
* Update setBack by loc.
* @param setBack
* @param loc
* @throws NullPointerException if loc.getWorld() is null.
*/
public static final void set(final Location setBack, final PlayerLocation loc) {
setBack.setWorld(loc.getWorld());
setBack.setWorld(testWorld(loc.getWorld()));
setBack.setX(loc.getX());
setBack.setY(loc.getY());
setBack.setZ(loc.getZ());
setBack.setYaw(loc.getYaw());
setBack.setPitch(loc.getPitch());
}
/**
* Throw a NullPointerException if world is null.
* @param world
* @return
*/
private static World testWorld(final World world) {
if (world == null) {
throw new NullPointerException("World must not be null.");
} else {
return world;
}
}
/**
* Quick out of bounds check for yaw.
* @param yaw
* @return
*/
public static final boolean needsYawCorrection(final float yaw) {
return yaw == Float.NaN || yaw < 0f || yaw >= 360f;
}
/**
* Quick out of bounds check for pitch.
* @param pitch
* @return
*/
public static final boolean needsPitchCorrection(final float pitch) {
return pitch == Float.NaN || pitch < -90f || pitch > 90f;
}
/**
* Quick out of bounds check for yaw and pitch.
* @param yaw
* @param pitch
* @return
*/
public static final boolean needsDirectionCorrection(final float yaw, final float pitch) {
return needsYawCorrection(yaw) || needsPitchCorrection(pitch);
}
/**
* Ensure 0 <= yaw < 360.
* @param yaw
* @return
*/
public static final float correctYaw(float yaw) {
if (yaw == Float.NaN) {
return 0f;
}
if (yaw >= 360f) {
if (yaw > 10000f) {
yaw = 0f;
} else {
while (yaw > 360f) {
yaw -= 360f;
}
}
}
if (yaw < 0f) {
if (yaw < -10000f) {
yaw = 0f;
} else {
while (yaw < 0f) {
yaw += 360f;
}
}
}
return yaw;
}
/**
* Ensure -90 <= pitch <= 90.
* @param pitch
* @return
*/
public static final float correctPitch(float pitch) {
if (pitch == Float.NaN) {
return 0f;
} else if (pitch < -90f) {
return -90f;
} else if (pitch > 90f) {
return 90f;
} else {
return pitch;
}
}
}

View File

@ -0,0 +1,242 @@
package fr.neatmonster.nocheatplus.checks.moving;
import java.util.Iterator;
import fr.neatmonster.nocheatplus.utilities.TrigUtil;
/**
* This class is meant to record locations for players moving, in order to allow to be more
* lenient for the case of latency for player-player interaction such as with fighting.
* <br>
* NOTES on intended use:<br>
* <li>Is meant to always carry some location.</li>
* <li>Records only the end-positions of a move.</li>
* <li>Prefer calling add(...) with the current location, before iterating. Alternative: guard with isEmpty().</li>
* <li>Updating on teleport events is not intended - if the distance is too big, Minecraft should prevent interaction anyway.</li>
* @author mc_dev
*
*/
public class LocationTrace {
public static final class TraceEntry {
/** We keep it open, if ticks or ms are used. */
public long time;
/** Coordinates. */
public double x, y, z;
public double lastDistSq;
public void set(long time, double x, double y, double z, double lastDistSq) {
this.x = x;
this.y = y;
this.z = z;
this.time = time;
this.lastDistSq = lastDistSq;
}
}
/**
* Iterate from oldest to latest. Not a fully featured Iterator.
* @author mc_dev
*
*/
public static final class TraceIterator implements Iterator<TraceEntry>{
private final TraceEntry[] entries;
/** Index as in LocationTrace */
private final int index;
private final int size;
private int currentIndex;
private final boolean ascend;
protected TraceIterator(TraceEntry[] entries, int index, int size, int currentIndex, boolean ascend) {
if (currentIndex >= entries.length || currentIndex < 0 ||
currentIndex <= index - size || currentIndex > index && currentIndex <= index - size + entries.length) {
// This should also prevent iterators for size == 0, for the moment (!).
throw new IllegalArgumentException("startIndex out of bounds.");
}
this.entries = entries;
this.index = index;
this.size = size;
this.currentIndex = currentIndex;
this.ascend = ascend;
}
@Override
public final TraceEntry next() {
if (!hasNext()) {
throw new IndexOutOfBoundsException("No more entries to iterate.");
}
final TraceEntry entry = entries[currentIndex];
if (ascend) {
currentIndex ++;
if (currentIndex >= entries.length) {
currentIndex = 0;
}
int ref = index - size + 1;
if (ref < 0) {
ref += entries.length;
}
if (currentIndex == ref) {
// Invalidate the iterator.
currentIndex = -1;
}
} else {
currentIndex --;
if (currentIndex < 0) {
currentIndex = entries.length - 1;
}
if (currentIndex == index) {
// Invalidate the iterator.
currentIndex = - 1;
}
}
return entry;
}
@Override
public final boolean hasNext() {
// Just check if currentIndex is within range.
return currentIndex >= 0 && currentIndex <= index && currentIndex > index - size || currentIndex > index && currentIndex >= index - size + entries.length;
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
}
/** A Ring. */
private final TraceEntry[] entries;
/** Last element index. */
private int index = -1;
/** Number of valid entries. */
private int size = 0;
private final double mergeDist;
private final double mergeDistSq;
// (No world name stored: Should be reset on world changes.)
public LocationTrace(int bufferSize, double mergeDist) {
// TODO: Might consider a cut-off distance/age (performance saving for iteration).
if (bufferSize < 1) {
throw new IllegalArgumentException("Expect bufferSize > 0, got instead: " + bufferSize);
}
entries = new TraceEntry[bufferSize];
for (int i = 0; i < bufferSize; i++) {
entries[i] = new TraceEntry();
}
this.mergeDist = mergeDist;
this.mergeDistSq = mergeDist * mergeDist;
}
public final void addEntry(final long time, final double x, final double y, final double z) {
double lastDistSq = 0.0;
if (size > 0) {
final TraceEntry latestEntry = entries[index];
// TODO: Consider duration of staying there ?
if (x == latestEntry.x && y == latestEntry.y && z == latestEntry.z) {
latestEntry.time = time;
return;
}
lastDistSq = TrigUtil.distanceSquared(x, y, z, latestEntry.x, latestEntry.y, latestEntry.z);
// TODO: Think about minMergeSize (1 = never merge the first two, size = first fill the ring).
if (size > 1 && lastDistSq <= mergeDistSq) {
// TODO: Could use Manhattan, after all.
// Only merge if last distance was not greater than mergeDist, to prevent too-far-off entries.
if (latestEntry.lastDistSq <= mergeDistSq) {
// Update lastDistSq, due to shifting the elements position.
final TraceEntry secondLatest = index - 1 < 0 ? entries[index - 1 + entries.length] : entries[index - 1];
lastDistSq = TrigUtil.distanceSquared(x, y, z, secondLatest.x, secondLatest.y, secondLatest.z);
latestEntry.set(time, x, y, z, lastDistSq);
return;
}
}
}
// Advance index.
index++;
if (index == entries.length) {
index = 0;
}
if (size < entries.length) {
size ++;
}
final TraceEntry newEntry = entries[index];
newEntry.set(time, x, y, z, lastDistSq);
}
/** Reset content pointers - call with world changes. */
public void reset() {
index = 0;
size = 0;
}
/**
* Get the actual number of valid elements. After some time of moving this should be entries.length.
* @return
*/
public int size() {
return size;
}
public boolean isEmpty() {
return size == 0;
}
/**
* Get size of ring buffer (maximal possible number of elements).
* @return
*/
public int getMaxSize() {
return entries.length;
}
public double getMergeDist() {
return mergeDist;
}
/**
* Iterate from latest to oldest.
* @return
*/
public TraceIterator latestIterator() {
return new TraceIterator(entries, index, size, index, false);
}
/**
* Iterate from oldest to latest.
* @return
*/
public TraceIterator oldestIterator() {
final int currentIndex = index - size + 1;
return new TraceIterator(entries, index, size, currentIndex < 0 ? currentIndex + entries.length : currentIndex, true);
}
/**
* Iterate from entry with max. age to latest, always includes latest.
* @param tick Absolute tick value for oldest accepted tick.
* @param ms Absolute ms value for oldest accepted ms;
* @return
*/
public TraceIterator maxAgeIterator(long time) {
int currentIndex = index;
int tempIndex = currentIndex;
int steps = 1;
while (steps < size) {
tempIndex --;
if (tempIndex < 0) {
tempIndex += size;
}
final TraceEntry entry = entries[tempIndex];
if (entry.time >= time) {
// Continue.
currentIndex = tempIndex;
} else {
break;
}
steps ++;
}
return new TraceIterator(entries, index, size, currentIndex, true);
}
}

View File

@ -60,8 +60,12 @@ public class MorePackets extends Check {
if (!data.hasMorePacketsSetBack()){
// TODO: Check if other set-back is appropriate or if to set on other events.
if (data.hasSetBack()) data.setMorePacketsSetBack(data.getSetBack(to));
else data.setMorePacketsSetBack(from);
if (data.hasSetBack()) {
data.setMorePacketsSetBack(data.getSetBack(to));
}
else {
data.setMorePacketsSetBack(from);
}
}
// Take a packet from the buffer.
@ -76,10 +80,8 @@ public class MorePackets extends Check {
// Execute whatever actions are associated with this check and the violation level and find out if we should
// cancel the event.
if (executeActions(player, data.morePacketsVL, -data.morePacketsBuffer,
MovingConfig.getConfig(player).morePacketsActions)){
if (executeActions(player, data.morePacketsVL, -data.morePacketsBuffer, MovingConfig.getConfig(player).morePacketsActions)){
newTo = data.getMorePacketsSetBack();
data.setTeleported(newTo);
}
}
@ -93,23 +95,28 @@ public class MorePackets extends Check {
// If there was a long pause (maybe server lag?), allow buffer to grow up to 100.
if (seconds > 2) {
if (data.morePacketsBuffer > 100)
data.morePacketsBuffer = 100;
} else if (data.morePacketsBuffer > 50)
if (data.morePacketsBuffer > 100) {
data.morePacketsBuffer = 100;
}
} else if (data.morePacketsBuffer > 50) {
// Only allow growth up to 50.
data.morePacketsBuffer = 50;
}
// Set the new "last" time.
data.morePacketsLastTime = time;
// Set the new "setback" location.
if (newTo == null) data.setMorePacketsSetBack(from);
} else if (data.morePacketsLastTime > time)
if (newTo == null) {
data.setMorePacketsSetBack(from);
}
} else if (data.morePacketsLastTime > time) {
// Security check, maybe system time changed.
data.morePacketsLastTime = time;
data.morePacketsLastTime = time;
}
if (newTo == null)
return null;
if (newTo == null) {
return null;
}
// Compose a new location based on coordinates of "newTo" and viewing direction of "event.getTo()" to allow the
// player to look somewhere else despite getting pulled back by NoCheatPlus.

View File

@ -13,6 +13,9 @@ import fr.neatmonster.nocheatplus.utilities.PlayerLocation;
*
*/
public class MoveInfo {
/** For temporary use. Might need cloning for passing to external API. Only use after calling MoveInfo.set! */
public final Location useLoc = new Location(null, 0, 0, 0);
public final BlockCache cache;
public final PlayerLocation from;
public final PlayerLocation to;
@ -24,24 +27,31 @@ public class MoveInfo {
}
/**
* Demands at least setting from.
* Initialize from, and if given to. Note that useLoc is left untouched (!).
* @param player
* @param from
* @param to
* @param from Must not be null.
* @param to Can be null.
* @param yOnGround
*/
public final void set(final Player player, final Location from, final Location to, final double yOnGround){
this.cache.setAccess(from.getWorld());
this.from.set(from, player, yOnGround);
this.cache.setAccess(from.getWorld());
this.from.setBlockCache(cache);
if (to != null){
this.to.set(to, player, yOnGround);
this.to.setBlockCache(cache);
}
// Note: using set to reset to by passing null won't work.
}
/**
* Clear caches and remove World references and such. Also resets the world of useLoc.
*/
public final void cleanup(){
useLoc.setWorld(null);
from.cleanup();
to.cleanup();
cache.cleanup();
}
}

View File

@ -137,8 +137,16 @@ public class MovingConfig extends ACheckConfig {
public final long sprintingGrace;
public final boolean assumeSprint;
public final int speedGrace;
public final boolean enforceLocation;
// Vehicles
public final boolean vehicleEnforceLocation;
public final boolean vehiclePreventDestroyOwn;
// Trace
public final int traceSize;
public final double traceMergeDist;
/**
* Instantiates a new moving configuration.
@ -214,9 +222,14 @@ public class MovingConfig extends ACheckConfig {
sprintingGrace = Math.max(0L, (long) (config.getDouble(ConfPaths.MOVING_SPRINTINGGRACE) * 1000.0)); // Config: seconds.
assumeSprint = config.getBoolean(ConfPaths.MOVING_ASSUMESPRINT);
speedGrace = Math.max(0, (int) Math.round(config.getDouble(ConfPaths.MOVING_SPEEDGRACE) * 20.0)); // Config: seconds
enforceLocation = config.getBoolean(ConfPaths.MOVING_ENFORCELOCATION);
vehicleEnforceLocation = config.getBoolean(ConfPaths.MOVING_VEHICLES_ENFORCELOCATION);
vehiclePreventDestroyOwn = config.getBoolean(ConfPaths.MOVING_VEHICLES_PREVENTDESTROYOWN);
traceSize = config.getInt(ConfPaths.MOVING_TRACE_SIZE);
traceMergeDist = config.getDouble(ConfPaths.MOVING_TRACE_MERGEDIST);
}

View File

@ -57,9 +57,13 @@ public class MovingData extends ACheckData {
* @return the data
*/
public static MovingData getData(final Player player) {
if (!playersMap.containsKey(player.getName()))
playersMap.put(player.getName(), new MovingData());
return playersMap.get(player.getName());
// Note that the trace might be null after just calling this.
MovingData data = playersMap.get(player.getName());
if (data == null) {
data = new MovingData();
playersMap.put(player.getName(), data);
}
return data;
}
public static ICheckData removeData(final String playerName) {
@ -81,6 +85,12 @@ public class MovingData extends ACheckData {
}
}
public static void onReload() {
for (final MovingData data : playersMap.values()) {
data.deleteTrace(); // Safe side.
}
}
/////////////////
// Not static.
/////////////////
@ -119,6 +129,8 @@ public class MovingData extends ACheckData {
public double fromX = Double.MAX_VALUE, fromY, fromZ;
/** Last to coordinates. */
public double toX = Double.MAX_VALUE, toY, toZ;
/** Moving trace (to positions). This is initialized on "playerJoins, i.e. MONITOR, and set to null on playerLeaves."*/
private LocationTrace trace = null;
// sf rather
/** To/from was ground or web or assumed to be etc. */
@ -269,8 +281,12 @@ public class MovingData extends ACheckData {
* @param loc
*/
public void resetPositions(final Location loc) {
if (loc == null) resetPositions(Double.MAX_VALUE, 0, 0);
else resetPositions(loc.getX(), loc.getY(), loc.getZ());
if (loc == null) {
resetPositions(Double.MAX_VALUE, 0, 0);
}
else {
resetPositions(loc.getX(), loc.getY(), loc.getZ());
}
}
/**
@ -278,8 +294,12 @@ public class MovingData extends ACheckData {
* @param loc
*/
public void resetPositions(PlayerLocation loc) {
if (loc == null) resetPositions(Double.MAX_VALUE, 0, 0);
else resetPositions(loc.getX(), loc.getY(), loc.getZ());
if (loc == null) {
resetPositions(Double.MAX_VALUE, 0, 0);
}
else {
resetPositions(loc.getX(), loc.getY(), loc.getZ());
}
}
/**
@ -375,8 +395,12 @@ public class MovingData extends ACheckData {
}
public boolean hasSetBackWorldChanged(final Location loc) {
if (setBack == null) return true;
else return setBack.getWorld().equals(loc.getWorld());
if (setBack == null) {
return true;
}
else {
return setBack.getWorld().equals(loc.getWorld());
}
}
@ -418,13 +442,21 @@ public class MovingData extends ACheckData {
}
public final void setMorePacketsSetBack(final PlayerLocation loc) {
if (morePacketsSetback == null) morePacketsSetback = loc.getLocation();
else LocUtil.set(morePacketsSetback, loc);
if (morePacketsSetback == null) {
morePacketsSetback = loc.getLocation();
}
else {
LocUtil.set(morePacketsSetback, loc);
}
}
public final void setMorePacketsSetBack(final Location loc) {
if (morePacketsSetback == null) morePacketsSetback = LocUtil.clone(loc);
else LocUtil.set(morePacketsSetback, loc);
if (morePacketsSetback == null) {
morePacketsSetback = LocUtil.clone(loc);
}
else {
LocUtil.set(morePacketsSetback, loc);
}
}
public Location getMorePacketsSetBack() {
@ -436,13 +468,21 @@ public class MovingData extends ACheckData {
}
public final void setMorePacketsVehicleSetBack(final PlayerLocation loc) {
if (morePacketsVehicleSetback == null) morePacketsVehicleSetback = loc.getLocation();
else LocUtil.set(morePacketsVehicleSetback, loc);
if (morePacketsVehicleSetback == null) {
morePacketsVehicleSetback = loc.getLocation();
}
else {
LocUtil.set(morePacketsVehicleSetback, loc);
}
}
public final void setMorePacketsVehicleSetBack(final Location loc) {
if (morePacketsVehicleSetback == null) morePacketsVehicleSetback = LocUtil.clone(loc);
else LocUtil.set(morePacketsVehicleSetback, loc);
if (morePacketsVehicleSetback == null) {
morePacketsVehicleSetback = LocUtil.clone(loc);
}
else {
LocUtil.set(morePacketsVehicleSetback, loc);
}
}
public final Location getMorePacketsVehicleSetBack() {
@ -617,6 +657,7 @@ public class MovingData extends ACheckData {
*/
public void onPlayerLeave() {
removeAllVelocity();
deleteTrace();
}
/**
@ -665,4 +706,67 @@ public class MovingData extends ACheckData {
}
}
/**
* This tests for a LocationTrace instance being set at all, not for locations having been added.
* @return
*/
public boolean hasTrace() {
return trace != null;
}
/**
* Convenience: Access method to simplify coding, being aware of some plugins using Player implementations as NPCs, leading to traces not being present.
* @return
*/
public LocationTrace getTrace(final Player player) {
if (trace == null) {
final MovingConfig cc = MovingConfig.getConfig(player);
trace = new LocationTrace(cc.traceSize, cc.traceMergeDist);
}
return trace;
}
/**
* Convenience
* @param player
* @param loc
*/
public void resetTrace(final Player player, final Location loc, final long time) {
final MovingConfig cc = MovingConfig.getConfig(player);
resetTrace(loc, time, cc.traceSize, cc.traceMergeDist);
}
/**
* Convenience method to add a location to the trace, creates the trace if necessary.
* @param player
* @param loc
* @param time
* @return Updated LocationTrace instance, for convenient use, without sticking too much to MovingData.
*/
public LocationTrace updateTrace(final Player player, final Location loc, final long time) {
final LocationTrace trace = getTrace(player);
trace.addEntry(time, loc.getX(), loc.getY(), loc.getZ());
return trace;
}
/**
* Convenience: Create or just reset the trace, add the current location.
* @param loc
* @param size
* @param mergeDist
* @param traceMergeDist
*/
public void resetTrace(final Location loc, final long time, final int size, double mergeDist) {
if (trace == null || trace.getMaxSize() != size || trace.getMergeDist() != mergeDist) {
trace = new LocationTrace(size, mergeDist);
} else {
trace.reset();
}
trace.addEntry(time, loc.getX(), loc.getY(), loc.getZ());
}
public void deleteTrace() {
trace = null;
}
}

View File

@ -114,7 +114,9 @@ public class MovingListener extends CheckListener implements TickListener, IRemo
event.setTo(setBack);
restored = true;
}
else data.resetSetBack();
else {
data.resetSetBack();
}
}
if (!restored) {
pLoc.set(loc, player);
@ -125,13 +127,16 @@ public class MovingListener extends CheckListener implements TickListener, IRemo
}
}
pLoc.cleanup();
if (!restored && MovingConfig.getConfig(player).tempKickIllegal) {
// TODO: correct the location ?
NCPAPIProvider.getNoCheatPlusAPI().denyLogin(player.getName(), 24L * 60L * 60L * 1000L);
LogUtil.logSevere("[NCP] could not restore location for " + player.getName() + " deny login for 24 hours");
if (!restored) {
// TODO: reset the bounding box of the player ?
if (MovingConfig.getConfig(player).tempKickIllegal) {
NCPAPIProvider.getNoCheatPlusAPI().denyLogin(player.getName(), 24L * 60L * 60L * 1000L);
LogUtil.logSevere("[NCP] could not restore location for " + player.getName() + ", kicking them and deny login for 24 hours");
} else {
LogUtil.logSevere("[NCP] could not restore location for " + player.getName() + ", kicking them.");
}
CheckUtils.kickIllegalMove(player);
}
// TODO: reset the bounding box of the player ?
CheckUtils.kickIllegalMove(player);
}
@ -170,12 +175,19 @@ public class MovingListener extends CheckListener implements TickListener, IRemo
*/
private final Map<String, PlayerMoveEvent> processingEvents = new HashMap<String, PlayerMoveEvent>();
private final Set<String> hoverTicks = new LinkedHashSet<String>(30);
/** Player names to check hover for, case insensitive. */
private final Set<String> hoverTicks = new LinkedHashSet<String>(30); // TODO: Rename
/** Player names to check enforcing the location for in onTick, case insensitive. */
private final Set<String> playersEnforce = new LinkedHashSet<String>(30);
private int hoverTicksStep = 5;
private final Set<EntityType> normalVehicles = new HashSet<EntityType>();
/** Location for temporary use with getLocation(useLoc). Always call setWorld(null) after use. Use LocUtil.clone before passing to other API. */
private final Location useLoc = new Location(null, 0, 0, 0); // TODO: Put to use...
public MovingListener() {
super(CheckType.MOVING);
}
@ -212,17 +224,18 @@ public class MovingListener extends CheckListener implements TickListener, IRemo
if (!data.hasSetBack() || blockY + 1D < data.getSetBackY()) return;
final Location loc = player.getLocation();
final Location loc = player.getLocation(useLoc);
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
&& (canJumpOffTop(mat.getId()) || BlockProperties.isLiquid(mat.getId()))) {
&& (canJumpOffTop(mat) || BlockProperties.isLiquid(mat))) {
// 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.setSetBackY(blockY + 1D);
data.sfJumpPhase = 0;
}
useLoc.setWorld(null);
}
/**
@ -230,9 +243,9 @@ public class MovingListener extends CheckListener implements TickListener, IRemo
* @param id
* @return
*/
private static boolean canJumpOffTop(final int id) {
private static boolean canJumpOffTop(final Material blockType) {
// TODO: Test if this can be removed!
return BlockProperties.isGround(id) || BlockProperties.isSolid(id);
return BlockProperties.isGround(blockType) || BlockProperties.isSolid(blockType);
}
/**
@ -261,28 +274,29 @@ public class MovingListener extends CheckListener implements TickListener, IRemo
if (bedLeave.isEnabled(player) && bedLeave.checkBed(player)) {
// Check if the player has to be reset.
// To "cancel" the event, we teleport the player.
final Location loc = player.getLocation();
final Location loc = player.getLocation(useLoc);
final MovingData data = MovingData.getData(player);
final MovingConfig cc = MovingConfig.getConfig(player);
Location target = null;
final boolean sfCheck = shouldCheckSurvivalFly(player, data, cc);
if (sfCheck) target = data.getSetBack(loc);
if (sfCheck) {
target = data.getSetBack(loc);
}
if (target == null) {
// TODO: Add something to guess the best set back location (possibly data.guessSetBack(Location)).
target = loc;
target = LocUtil.clone(loc);
}
if (target != null) {
// Actually this should not possibly be null, this is a block for "future" purpose, feel free to criticize it.
if (sfCheck && cc.sfFallDamage && noFall.isEnabled(player)) {
// Check if to deal damage.
double y = loc.getY();
if (data.hasSetBack()) y = Math.min(y, data.getSetBackY());
noFall.checkDamage(player, data, y);
}
// Teleport.
data.setTeleported(target); // Should be enough. | new Location(target.getWorld(), target.getX(), target.getY(), target.getZ(), target.getYaw(), target.getPitch());
player.teleport(target, TeleportCause.PLUGIN);// TODO: schedule / other measures ?
if (sfCheck && cc.sfFallDamage && noFall.isEnabled(player)) {
// Check if to deal damage.
double y = loc.getY();
if (data.hasSetBack()) y = Math.min(y, data.getSetBackY());
noFall.checkDamage(player, data, y);
}
// Cleanup
useLoc.setWorld(null);
// Teleport.
data.prepareSetBack(target); // Should be enough. | new Location(target.getWorld(), target.getX(), target.getY(), target.getZ(), target.getYaw(), target.getPitch());
player.teleport(target, TeleportCause.PLUGIN);// TODO: schedule / other measures ?
}
else{
// Reset bed ...
@ -303,10 +317,19 @@ public class MovingListener extends CheckListener implements TickListener, IRemo
// Maybe this helps with people teleporting through Multiverse portals having problems?
final Player player = event.getPlayer();
final MovingData data = MovingData.getData(player);
final MovingConfig cc = MovingConfig.getConfig(player);
data.clearFlyData();
data.clearMorePacketsData();
// TODO: Might omit this if neither check is activated.
data.setSetBack(player.getLocation());
final Location loc = player.getLocation(useLoc);
data.setSetBack(loc);
data.resetPositions(loc);
data.resetTrace(loc, TickTask.getTick(), cc.traceSize, cc.traceMergeDist);
if (cc.enforceLocation) {
// Just in case.
playersEnforce.add(player.getName());
}
useLoc.setWorld(null);
}
/**
@ -348,6 +371,12 @@ public class MovingListener extends CheckListener implements TickListener, IRemo
final Location to = event.getTo();
Location newTo = null;
// // Check problematic yaw/pitch values.
// if (LocUtil.needsDirectionCorrection(from.getYaw(), from.getPitch())
// || LocUtil.needsDirectionCorrection(to.getYaw(), to.getPitch())) {
// DataManager.getPlayerData(player).task.correctDirection();
// }
// TODO: Check illegal moves here anyway (!).
// TODO: Check if vehicle move logs correctly (fake).
@ -371,23 +400,38 @@ public class MovingListener extends CheckListener implements TickListener, IRemo
// Ignore changing worlds.
earlyReturn = true;
} else {
// COntinue with full processing.
earlyReturn = false;
}
// TODO: Might log base parts here (+extras).
if (earlyReturn) {
// TODO: Remove player from enforceLocation ?
// TODO: Log "early return: " + tags.
if (newTo != null) {
// Illegal Yaw/Pitch.
if (LocUtil.needsYawCorrection(newTo.getYaw())) {
newTo.setYaw(LocUtil.correctYaw(newTo.getYaw()));
}
if (LocUtil.needsPitchCorrection(newTo.getPitch())) {
newTo.setPitch(LocUtil.correctPitch(newTo.getPitch()));
}
// Set.
// TODO: Reset positions? enforceLocation?
event.setTo(newTo);
}
return;
}
// newTo should be null here.
// TODO: Order this to above "early return"?
// Set up data / caching.
final MoveInfo moveInfo;
if (parkedInfo.isEmpty()) moveInfo = new MoveInfo(mcAccess);
else moveInfo = parkedInfo.remove(parkedInfo.size() - 1);
if (parkedInfo.isEmpty()) {
moveInfo = new MoveInfo(mcAccess);
}
else {
moveInfo = parkedInfo.remove(parkedInfo.size() - 1);
}
final MovingConfig cc = MovingConfig.getConfig(player);
moveInfo.set(player, from, to, cc.yOnGround);
// TODO: Data resetting above ?
@ -405,6 +449,19 @@ public class MovingListener extends CheckListener implements TickListener, IRemo
return;
}
// The players location.
final Location loc = (cc.noFallCheck || cc.passableCheck) ? player.getLocation(moveInfo.useLoc) : null;
// Check for location consistency.
if (cc.enforceLocation && playersEnforce.contains(playerName)) {
// NOTE: The setback should not be set before this, even if not yet set.
// Last to vs. from.
newTo = enforceLocation(player, from, data);
// TODO: Remove anyway ?
playersEnforce.remove(playerName);
}
final long time = System.currentTimeMillis();
if (player.isSprinting() || cc.assumeSprint) {
// Hard to confine assumesprint further (some logics change with hdist or sprinting).
@ -444,10 +501,6 @@ public class MovingListener extends CheckListener implements TickListener, IRemo
final int tick = TickTask.getTick();
data.removeInvalidVelocity(tick - cc.velocityActivationTicks);
data.velocityTick();
// The players location.
// TODO: Change to getLocation(moveInfo.loc) once 1.4.5 support is dropped.
final Location loc = (cc.noFallCheck || cc.passableCheck) ? player.getLocation() : null;
// Check passable first to prevent set-back override.
// TODO: Redesign to set set-backs later (queue + invalidate).
@ -564,30 +617,21 @@ public class MovingListener extends CheckListener implements TickListener, IRemo
}
}
// Did one of the checks decide we need a new "to"-location?
if (newTo != null) {
// Reset some data.
data.prepareSetBack(newTo);
// Set new to-location.
// TODO: Clone here for the case of using loc with loc = player.getLocation(moveInfo.loc).
// TODO: Actually should be a newly created location already (data.getSetBack).
event.setTo(newTo);
// Debug.
if (cc.debug) {
System.out.println(player.getName() + " set back to: " + newTo.getWorld() + StringUtil.fdec3.format(newTo.getX()) + ", " + StringUtil.fdec3.format(newTo.getY()) + ", " + StringUtil.fdec3.format(newTo.getZ()));
}
}
// Set positions.
// TODO: Consider setting in Monitor (concept missing for changing coordinates, could double-check).
data.fromX = from.getX();
data.fromY = from.getY();
data.fromZ = from.getZ();
data.toX = to.getX();
data.toY = to.getY();
data.toZ = to.getZ();
if (newTo == null) {
// Set positions.
// TODO: Consider setting in Monitor (concept missing for changing coordinates, could double-check).
data.fromX = from.getX();
data.fromY = from.getY();
data.fromZ = from.getZ();
data.toX = to.getX();
data.toY = to.getY();
data.toZ = to.getZ();
}
else {
// Set-back handling.
onSetBack(player, event, newTo, data, cc);
}
// Cleanup.
moveInfo.cleanup();
@ -595,6 +639,36 @@ public class MovingListener extends CheckListener implements TickListener, IRemo
}
/**
*
* @param player
* @param event
* @param newTo Must be a cloned or new Location instance, free for whatever other plugins do with it.
* @param data
* @param cc
*/
private void onSetBack(final Player player, final PlayerMoveEvent event, final Location newTo, final MovingData data, final MovingConfig cc) {
// Illegal Yaw/Pitch.
if (LocUtil.needsYawCorrection(newTo.getYaw())) {
newTo.setYaw(LocUtil.correctYaw(newTo.getYaw()));
}
if (LocUtil.needsPitchCorrection(newTo.getPitch())) {
newTo.setPitch(LocUtil.correctPitch(newTo.getPitch()));
}
// Reset some data.
data.prepareSetBack(newTo);
data.resetPositions(newTo); // TODO: Might move into prepareSetBack, experimental here.
// Set new to-location.
event.setTo(newTo);
// Debug.
if (cc.debug) {
System.out.println(player.getName() + " set back to: " + newTo.getWorld() + StringUtil.fdec3.format(newTo.getX()) + ", " + StringUtil.fdec3.format(newTo.getY()) + ", " + StringUtil.fdec3.format(newTo.getZ()));
}
}
/**
* Called from player-move checking, if the player is inside of a vehicle.
* @param player
* @param from
@ -612,7 +686,7 @@ public class MovingListener extends CheckListener implements TickListener, IRemo
data.sfLowJump = false;
// TODO: What with processingEvents.remove(player.getName());
if (vehicle != null) {
final Location vLoc = vehicle.getLocation();
final Location vLoc = vehicle.getLocation(); // TODO: Use a location as argument.
// (Auto detection of missing events, might fire one time too many per plugin run.)
if (!normalVehicles.contains(vehicle.getType())) {
onVehicleMove(vehicle, vLoc, vLoc, true);
@ -675,12 +749,14 @@ public class MovingListener extends CheckListener implements TickListener, IRemo
// Feed combined check.
final CombinedData data = CombinedData.getData(player);
data.lastMoveTime = now;
data.lastMoveTime = now; // TODO: Evaluate moving this to MovingData !?
final Location from = event.getFrom();
final String fromWorldName = from.getWorld().getName();
// Feed yawrate and reset moving data positions if necessary.
final MovingData mData = MovingData.getData(player);
final long time = TickTask.getTick();
if (!event.isCancelled()) {
final Location to = event.getTo();
final String toWorldName = to.getWorld().getName();
@ -688,20 +764,26 @@ public class MovingListener extends CheckListener implements TickListener, IRemo
// TODO: maybe even not count vehicles at all ?
if (player.isInsideVehicle()) {
// TODO: refine (!).
MovingData.getData(player).resetPositions(player.getVehicle().getLocation());
final Location ref = player.getVehicle().getLocation(useLoc);
mData.resetPositions(ref);
useLoc.setWorld(null);
mData.resetTrace(player, ref, time);
}
else if (!fromWorldName.equals(toWorldName)) {
MovingData.getData(player).resetPositions(to);
mData.resetPositions(to);
mData.resetTrace(player, to, time);
}
else{
// Slightly redundant at present.
MovingData.getData(player).setTo(to);
mData.setTo(to);
mData.resetTrace(player, to, time);
}
}
else {
// TODO: teleported + other resetting ?
Combined.feedYawRate(player, from.getYaw(), now, fromWorldName, data);
MovingData.getData(player).resetPositions(from);
mData.resetPositions(from);
mData.resetTrace(player, from, time); // TODO: Should probably leave this to the teleport event!
}
}
@ -719,31 +801,6 @@ public class MovingListener extends CheckListener implements TickListener, IRemo
data.clearMorePacketsData();
// TODO: This event might be redundant (!).
}
/**
* When a player respawns, all information related to the moving checks
* becomes invalid.
*
* @param event
* the event
*/
@EventHandler(priority = EventPriority.MONITOR)
public void onPlayerRespawn(final PlayerRespawnEvent event) {
final Player player = event.getPlayer();
final MovingData data = MovingData.getData(player);
data.clearFlyData();
data.clearMorePacketsData();
data.setSetBack(event.getRespawnLocation());
// TODO: consider data.resetPositions(data.setBack);
// (Not putting hover in at respawn due to chunk sending.)
// TODO: Might use grace ticks for this too (and bigger teleports).
// final MovingConfig cc = MovingConfig.getConfig(player);
// if (cc.sfHoverCheck) {
// // Assume the player might be hovering.
// data.sfHoverTicks = 0;
// hoverTicks.add(player.getName());
// }
}
/**
* Clear fly data on death.
@ -755,7 +812,8 @@ public class MovingListener extends CheckListener implements TickListener, IRemo
final MovingData data = MovingData.getData(player);
data.clearFlyData();
data.clearMorePacketsData();
data.setSetBack(player.getLocation()); // TODO: Monitor this change (!).
data.setSetBack(player.getLocation(useLoc)); // TODO: Monitor this change (!).
useLoc.setWorld(null);
}
/**
@ -843,7 +901,7 @@ public class MovingListener extends CheckListener implements TickListener, IRemo
event.setTo(ref);
}
else{
ref = from;
ref = from; // Player.getLocation ?
event.setCancelled(true);
}
}
@ -857,7 +915,7 @@ public class MovingListener extends CheckListener implements TickListener, IRemo
// public void run() {
// if (!data.hasSetBackWorldChanged(setBack)) { // && data.isSetBack(setBack)) {
// player.sendMessage("SETBACK FROM MC DERP.");
// player.teleport(setBack);
// player.teleport(setBack, TeleportCause.PLUGIN);
// }
// }
// });
@ -1016,11 +1074,11 @@ public class MovingListener extends CheckListener implements TickListener, IRemo
if (!from.getWorld().equals(to.getWorld())) return;
final MovingData data = MovingData.getData(player);
data.vehicleConsistency = MoveConsistency.getConsistency(from, to, player.getLocation());
data.vehicleConsistency = MoveConsistency.getConsistency(from, to, player.getLocation(useLoc));
switch (data.vehicleConsistency) {
case FROM:
case TO:
data.resetPositions(player.getLocation()); // TODO: Drop MC 1.4!
data.resetPositions(player.getLocation(useLoc)); // TODO: Drop MC 1.4!
break;
case INCONSISTENT:
// TODO: Any exploits exist? -> TeleportUtil.forceMount(player, vehicle)
@ -1062,26 +1120,40 @@ public class MovingListener extends CheckListener implements TickListener, IRemo
// TODO: Reset on world changes or not?
data.morePacketsVehicleTaskId = Bukkit.getScheduler().scheduleSyncDelayedTask(plugin, new VehicleSetBack(vehicle, player, newTo, cc.debug));
}
useLoc.setWorld(null);
}
@EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = false)
public void onEntityDamage(final EntityDamageEvent event) {
if (event.getCause() != DamageCause.FALL) return;
if (event.getCause() != DamageCause.FALL) {
return;
}
final Entity entity = event.getEntity();
if (!(entity instanceof Player)) return;
if (!(entity instanceof Player)) {
return;
}
final Player player = (Player) entity;
final MovingData data = MovingData.getData(player);
if (player.isInsideVehicle()) {
// Ignore vehicles (noFallFallDistance will be inaccurate anyway).
data.clearNoFallData();
return;
}
final MovingConfig cc = MovingConfig.getConfig(player);
if (event.isCancelled() || !shouldCheckSurvivalFly(player, data, cc) || !noFall.isEnabled(player)) {
data.clearNoFallData();
return;
}
final Location loc = player.getLocation();
final Location loc = player.getLocation(useLoc);
boolean allowReset = true;
if (!data.noFallSkipAirCheck) {
final MoveInfo moveInfo;
if (parkedInfo.isEmpty()) moveInfo = new MoveInfo(mcAccess);
else moveInfo = parkedInfo.remove(parkedInfo.size() - 1);
if (parkedInfo.isEmpty()) {
moveInfo = new MoveInfo(mcAccess);
}
else {
moveInfo = parkedInfo.remove(parkedInfo.size() - 1);
}
moveInfo.set(player, loc, null, cc.noFallyOnGround);
// NOTE: No isIllegal check here.
final PlayerLocation pLoc = moveInfo.from;
@ -1139,43 +1211,113 @@ public class MovingListener extends CheckListener implements TickListener, IRemo
}
}
// Entity fall-distance should be reset elsewhere.
// Cleanup.
useLoc.setWorld(null);
}
/**
* When a player respawns, all information related to the moving checks
* becomes invalid.
*
* @param event
* the event
*/
@EventHandler(priority = EventPriority.MONITOR)
public void onPlayerRespawn(final PlayerRespawnEvent event) {
final Player player = event.getPlayer();
final MovingData data = MovingData.getData(player);
final MovingConfig cc = MovingConfig.getConfig(player);
final Location loc = event.getRespawnLocation();
data.clearFlyData();
data.setSetBack(loc);
// Handle respawn like join.
dataOnJoin(player, loc, data, cc);
}
@Override
public void playerJoins(final Player player) {
final MovingData data = MovingData.getData(player);
// TODO: on existing set back: detect world changes and loss of world on join (+ set up some paradigm).
data.clearMorePacketsData();
data.removeAllVelocity();
final Location loc = player.getLocation();
final MovingConfig cc = MovingConfig.getConfig(player);
final Location loc = player.getLocation(useLoc);
// Correct set-back on world changes.
if (loc == null) {
// Bug on server side ?
// Correct set-back on join.
if (data.hasSetBackWorldChanged(loc)) {
data.clearFlyData();
data.setSetBack(loc);
}
else if (!data.hasSetBack()) {
// TODO: Might consider something else like with respawn. Check if it is passable ?
data.setSetBack(loc);
}
else if (data.hasSetBackWorldChanged(loc)) {
data.clearFlyData();
data.setSetBack(loc);
}
if (data.fromX == Double.MAX_VALUE && data.toX == Double.MAX_VALUE) {
// TODO: re-think: more fine grained reset?
data.resetPositions(loc);
dataOnJoin(player, loc, data, cc);
// Cleanup.
useLoc.setWorld(null);
}
/**
* Alter data for players joining (join, respawn).<br>
* Do before, if necessary:<br>
* <li>data.clearFlyData()</li>
* <li>data.setSetBack(...)</li>
* @param player
* @param loc Can be useLoc (!).
* @param data
* @param cc
*/
private void dataOnJoin(Player player, Location loc, MovingData data, MovingConfig cc) {
final int tick = TickTask.getTick();
// Check loaded chunks.
if (cc.loadChunksOnJoin) {
final int loaded = BlockCache.ensureChunksLoaded(loc.getWorld(), loc.getX(), loc.getZ(), 3.0);
if (loaded > 0 && cc.debug && BuildParameters.debugLevel > 0) {
// DEBUG
LogUtil.logInfo("[NoCheatPlus] Player join: Loaded " + loaded + " chunk" + (loaded == 1 ? "" : "s") + " for the world " + loc.getWorld().getName() + " for player: " + player.getName());
}
}
// Always reset position to this one.
// TODO: more fine grained reset?
data.resetPositions(loc);
data.clearMorePacketsData();
data.removeAllVelocity();
data.resetTrace(loc, tick, cc.traceSize, cc.traceMergeDist);
// More resetting.
data.vDistAcc.clear();
data.toWasReset = false;
data.fromWasReset = false;
data.toWasReset = BlockProperties.isOnGroundOrResetCond(player, loc, cc.yOnGround);
data.fromWasReset = data.toWasReset;
// Enforcing the location.
if (cc.enforceLocation) {
playersEnforce.add(player.getName());
}
// Hover.
final MovingConfig cc = MovingConfig.getConfig(player);
initHover(player, data, cc, data.toWasReset); // isOnGroundOrResetCond
// // Bad pitch/yaw, just in case.
// if (LocUtil.needsDirectionCorrection(useLoc.getYaw(), useLoc.getPitch())) {
// DataManager.getPlayerData(player).task.correctDirection();
// }
}
/**
* Initialize the hover check for a player (login, respawn).
* @param player
* @param data
* @param cc
* @param isOnGroundOrResetCond
*/
private void initHover(final Player player, final MovingData data, final MovingConfig cc, final boolean isOnGroundOrResetCond) {
// Reset hover ticks until a better method is used.
if (cc.sfHoverCheck) {
if (!isOnGroundOrResetCond && cc.sfHoverCheck) {
// Start as if hovering already.
// Could check shouldCheckSurvivalFly(player, data, cc), but this should be more sharp (gets checked on violation).
data.sfHoverTicks = 0;
@ -1186,16 +1328,6 @@ public class MovingListener extends CheckListener implements TickListener, IRemo
data.sfHoverLoginTicks = 0;
data.sfHoverTicks = -1;
}
// Check loaded chunks.
if (cc.loadChunksOnJoin) {
final int loaded = BlockCache.ensureChunksLoaded(loc.getWorld(), loc.getX(), loc.getZ(), 3.0);
if (loaded > 0 && cc.debug && BuildParameters.debugLevel > 0) {
// DEBUG
LogUtil.logInfo("[NoCheatPlus] Player join: Loaded " + loaded + " chunk" + (loaded == 1 ? "" : "s") + " for the world " + loc.getWorld().getName() + " for player: " + player.getName());
}
}
}
@Override
@ -1252,7 +1384,8 @@ public class MovingListener extends CheckListener implements TickListener, IRemo
final MovingData data = MovingData.getData(player);
data.removeAllVelocity();
// Event should have a vehicle, in case check this last.
data.vehicleConsistency = MoveConsistency.getConsistency(event.getVehicle().getLocation(), null, player.getLocation());
data.vehicleConsistency = MoveConsistency.getConsistency(event.getVehicle().getLocation(), null, player.getLocation(useLoc));
useLoc.setWorld(null); // TODO: A pool ?
// TODO: more resetting, visible check ?
}
@ -1272,7 +1405,7 @@ public class MovingListener extends CheckListener implements TickListener, IRemo
final MovingConfig cc = MovingConfig.getConfig(player);
// TODO: Loc can be inconsistent, determine which to use !
final Location pLoc = player.getLocation();
final Location pLoc = player.getLocation(useLoc);
Location loc = pLoc; // The location to use as set-back.
// TODO: Which vehicle to use ?
// final Entity vehicle = player.getVehicle();
@ -1290,7 +1423,7 @@ public class MovingListener extends CheckListener implements TickListener, IRemo
loc = vLoc; //
if (data.vehicleConsistency != MoveConsistency.INCONSISTENT) {
final Location oldLoc = new Location(pLoc.getWorld(), data.toX, data.toY, data.toZ);
if (MoveConsistency.getConsistency(oldLoc, null, pLoc) != MoveConsistency.INCONSISTENT) {
if (data.toX != Double.MAX_VALUE && MoveConsistency.getConsistency(oldLoc, null, pLoc) != MoveConsistency.INCONSISTENT) {
loc = oldLoc;
}
}
@ -1302,7 +1435,7 @@ public class MovingListener extends CheckListener implements TickListener, IRemo
}
// Adjust loc if in liquid (meant for boats !?).
if (BlockProperties.isLiquid(loc.getBlock().getTypeId())) {
if (BlockProperties.isLiquid(loc.getBlock().getType())) {
loc.setY(Location.locToBlock(loc.getY()) + 1.25);
}
@ -1318,6 +1451,7 @@ public class MovingListener extends CheckListener implements TickListener, IRemo
data.verticalFreedom = 1.2;
data.verticalVelocity = 0.15;
data.verticalVelocityUsed = 0;
useLoc.setWorld(null);
}
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
@ -1334,15 +1468,42 @@ public class MovingListener extends CheckListener implements TickListener, IRemo
@Override
public void onTick(final int tick, final long timeLast) {
// Hover checks !
final List<String> rem = new ArrayList<String>(hoverTicks.size()); // Pessimistic.
// TODO: Change to per world checking (as long as configs are per world).
// Enforcing location check.
for (final String playerName : playersEnforce) {
final Player player = DataManager.getPlayerExact(playerName);
if (player == null || !player.isOnline()) {
rem.add(playerName);
continue;
} else if (player.isDead() || player.isSleeping() || player.isInsideVehicle()) {
// Don't remove but also don't check [subject to change].
continue;
}
final MovingData data = MovingData.getData(player);
final Location newTo = enforceLocation(player, player.getLocation(useLoc), data);
if (newTo != null) {
data.prepareSetBack(newTo);
player.teleport(newTo, TeleportCause.PLUGIN);
}
}
if (!rem.isEmpty()) {
playersEnforce.removeAll(rem);
}
// Hover check (survivalfly).
rem.clear();
if (tick % hoverTicksStep != 0) {
// Only check every so and so ticks.
return;
}
final MoveInfo info;
if (parkedInfo.isEmpty()) info = new MoveInfo(mcAccess);
else info = parkedInfo.remove(parkedInfo.size() - 1);
final List<String> rem = new ArrayList<String>(hoverTicks.size()); // Pessimistic.
if (parkedInfo.isEmpty()) {
info = new MoveInfo(mcAccess);
}
else {
info = parkedInfo.remove(parkedInfo.size() - 1);
}
for (final String playerName : hoverTicks) {
// TODO: put players into the set (+- one tick would not matter ?)
// TODO: might add an online flag to data !
@ -1383,10 +1544,28 @@ public class MovingListener extends CheckListener implements TickListener, IRemo
rem.add(playerName);
}
}
info.cleanup(); // Just in case.
parkedInfo.add(info);
hoverTicks.removeAll(rem);
rem.clear();
info.cleanup();
parkedInfo.add(info);
useLoc.setWorld(null);
}
private Location enforceLocation(final Player player, final Location loc, final MovingData data) {
if (data.toX != Double.MAX_VALUE && TrigUtil.distanceSquared(data.toX, data.toY, data.toZ, loc.getX(), loc.getY(), loc.getZ()) > 1.0 / 256.0) {
// Teleport back.
// TODO: Add history / alert?
//player.sendMessage(ChatColor.RED + "NCP: enforce location !"); // TODO: DEBUG - REMOVE.
if (data.hasSetBack()) {
// Might have to re-check all context with playerJoins and keeping old set-backs...
// Could use a flexible set-back policy (switch to in-air on login).
return data.getSetBack(loc);
} else {
return new Location(player.getWorld(), data.toX, data.toY, data.toZ, loc.getYaw(), loc.getPitch());
}
} else {
return null;
}
}
/**
@ -1399,8 +1578,9 @@ public class MovingListener extends CheckListener implements TickListener, IRemo
*/
private boolean checkHover(final Player player, final MovingData data, final MovingConfig cc, final MoveInfo info) {
// Check if player is on ground.
final Location loc = player.getLocation();
final Location loc = player.getLocation(useLoc); // useLoc.setWorld(null) is done in onTick.
info.set(player, loc, null, cc.yOnGround);
// (Could use useLoc of MoveInfo here. Note orderm though.)
final boolean res;
// TODO: Collect flags, more margin ?
final int loaded = info.from.ensureChunksLoaded();
@ -1452,12 +1632,14 @@ public class MovingListener extends CheckListener implements TickListener, IRemo
@Override
public IData removeData(String playerName) {
hoverTicks.remove(playerName);
playersEnforce.remove(playerName);
return null;
}
@Override
public void removeAllData() {
hoverTicks.clear();
playersEnforce.clear();
parkedInfo.clear();
}
@ -1469,6 +1651,7 @@ public class MovingListener extends CheckListener implements TickListener, IRemo
}
parkedInfo.clear();
hoverTicksStep = Math.max(1, ConfigManager.getConfigFile().getInt(ConfPaths.MOVING_SURVIVALFLY_HOVER_STEP));
MovingData.onReload();
}
}

View File

@ -1,6 +1,7 @@
package fr.neatmonster.nocheatplus.checks.moving;
import org.bukkit.Bukkit;
import org.bukkit.GameMode;
import org.bukkit.Location;
import org.bukkit.entity.Player;
import org.bukkit.event.entity.EntityDamageEvent;
@ -16,6 +17,9 @@ import fr.neatmonster.nocheatplus.utilities.StringUtil;
* A check to see if people cheat by tricking the server to not deal them fall damage.
*/
public class NoFall extends Check {
/** For temporary use: LocUtil.clone before passing deeply, call setWorld(null) after use. */
private final Location useLoc = new Location(null, 0, 0, 0);
/**
* Instantiates a new no fall check.
@ -206,12 +210,21 @@ public class NoFall extends Check {
public void onLeave(final Player player) {
final MovingData data = MovingData.getData(player);
final float fallDistance = player.getFallDistance();
if (data.noFallFallDistance - fallDistance > 0){
// Might use tolerance, might log, might use method (compare: MovingListener.onEntityDamage).
// Might consider triggering violations here as well.
final float yDiff = (float) (data.noFallMaxY - player.getLocation().getY());
final float maxDist = Math.max(yDiff, Math.max(data.noFallFallDistance, fallDistance));
player.setFallDistance(maxDist);
if (data.noFallFallDistance - fallDistance > 0.0) {
final double playerY = player.getLocation(useLoc).getY();
useLoc.setWorld(null);
if (player.getAllowFlight() || player.isFlying() || player.getGameMode() == GameMode.CREATIVE) {
// Forestall potential issues with flying plugins.
player.setFallDistance(0f);
data.noFallFallDistance = 0f;
data.noFallMaxY = playerY;
} else {
// Might use tolerance, might log, might use method (compare: MovingListener.onEntityDamage).
// Might consider triggering violations here as well.
final float yDiff = (float) (data.noFallMaxY - playerY);
final float maxDist = Math.max(yDiff, Math.max(data.noFallFallDistance, fallDistance));
player.setFallDistance(maxDist);
}
}
}

View File

@ -136,7 +136,7 @@ public class Passable extends Check {
System.out.println(player.getName() + " Using set-back location for passable.");
}
} else if (cc.debug) {
System.out.println(player.getName() + " Ignorng set-back for passable.");
System.out.println(player.getName() + " Ignoring set-back for passable.");
}
}
@ -155,7 +155,8 @@ public class Passable extends Check {
// TODO: Consider another set back position for this, also keeping track of players moving around in blocks.
final Location newTo;
if (loc != null) {
newTo = loc;
// Ensure the given location is cloned.
newTo = LocUtil.clone(loc);
} else {
newTo = from.getLocation();
if (cc.debug) {

View File

@ -8,6 +8,7 @@ import java.util.Set;
import org.bukkit.Location;
import org.bukkit.entity.Player;
import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause;
import fr.neatmonster.nocheatplus.actions.ParameterName;
import fr.neatmonster.nocheatplus.checks.Check;
@ -65,6 +66,9 @@ public class SurvivalFly extends Check {
private final Set<String> reallySneaking = new HashSet<String>(30);
/** For temporary use: LocUtil.clone before passing deeply, call setWorld(null) after use. */
private final Location useLoc = new Location(null, 0, 0, 0);
/**
* Instantiates a new survival fly check.
*/
@ -148,8 +152,6 @@ public class SurvivalFly extends Check {
// Mixed checks (lost ground).
/////////////////////////////////
// data.stats.addStats(data.stats.getId("sfCheck", true), 1);
// "Lost ground" workaround.
if (fromOnGround || from.isResetCond()) {
@ -161,7 +163,6 @@ public class SurvivalFly extends Check {
// TODO: Consider if (!resetTo) ?
// Check lost-ground workarounds.
resetFrom = lostGround(player, from, to, hDistance, yDistance, sprinting, data, cc);
// data.stats.addStats(data.stats.getId("sfLostGround", true), resetFrom ? 1 : 0);
// Note: if not setting resetFrom, other places have to check assumeGround...
}
@ -428,7 +429,7 @@ public class SurvivalFly extends Check {
}
// Invalidation of vertical velocity.
if (data.verticalVelocityUsed > cc.velocityGraceTicks && yDistance <= 0 && data.sfLastYDist > 0) {
if (data.verticalVelocityUsed > cc.velocityGraceTicks && yDistance <= 0 && data.sfLastYDist > 0 && data.sfLastYDist != Double.MAX_VALUE) {
// data.verticalFreedom = 0; // TODO: <- why?
data.verticalVelocityCounter = 0;
data.verticalVelocity = 0;
@ -637,7 +638,7 @@ public class SurvivalFly extends Check {
if (cc.survivalFlyAccountingV) {
// Currently only for "air" phases.
// Vertical.
if (yDirChange && data.sfLastYDist > 0) {
if (yDirChange && data.sfLastYDist > 0) { // (Double.MAX_VALUE is checked above.)
// Change to descending phase.
data.vDistAcc.clear();
// Allow adding 0.
@ -719,6 +720,7 @@ public class SurvivalFly extends Check {
/**
* Check on change of y direction.
* <br>Note: data.sfLastYDist must not be Double.MAX_VALUE when calling this.
* @param yDistance
* @param vDistanceAboveLimit
* @return vDistanceAboveLimit
@ -737,7 +739,9 @@ public class SurvivalFly extends Check {
vDistanceAboveLimit = Math.max(vDistanceAboveLimit, Math.abs(yDistance));
tags.add("ychincfly");
}
else tags.add("ychincair");
else {
tags.add("ychincair");
}
}
}
else{
@ -869,7 +873,7 @@ public class SurvivalFly extends Check {
allowHop = false; // Magic!
// 2x horizontal speed increase detection.
if (hDistance - data.sfLastHDist >= walkSpeed * 0.5 && data.bunnyhopDelay == bunnyHopMax - 1) {
if (data.sfLastHDist != Double.MAX_VALUE && hDistance - data.sfLastHDist >= walkSpeed * 0.5 && data.bunnyhopDelay == bunnyHopMax - 1) {
if (data.sfLastYDist == 0.0 && (data.fromWasReset || data.toWasReset) && yDistance >= 0.4) {
// TODO: Confine to last was hop (according to so far input on this topic).
tags.add(DOUBLE_BUNNY);
@ -960,7 +964,7 @@ public class SurvivalFly extends Check {
// Check workarounds.
if (yDistance <= 0.5) {
// TODO: mediumLiftOff: refine conditions (general) , to should be near water level.
if (data.mediumLiftOff == MediumLiftOff.GROUND && !BlockProperties.isLiquid(from.getTypeIdAbove()) || !to.isInLiquid() || (toOnGround || data.sfLastYDist - yDistance >= 0.010 || to.isAboveStairs())) {
if (data.mediumLiftOff == MediumLiftOff.GROUND && !BlockProperties.isLiquid(from.getTypeIdAbove()) || !to.isInLiquid() || (toOnGround || data.sfLastYDist != Double.MAX_VALUE && data.sfLastYDist - yDistance >= 0.010 || to.isAboveStairs())) {
vAllowedDistance = walkSpeed * modSwim + 0.5;
vDistanceAboveLimit = yDistance - vAllowedDistance;
}
@ -1084,10 +1088,9 @@ public class SurvivalFly extends Check {
// Half block step up.
if (yDistance <= 0.5 && hDistance < 0.5 && setBackYDistance <= 1.3 + 0.2 * data.jumpAmplifier && to.isOnGround()) {
if (data.sfLastYDist < 0 || from.isOnGround(0.5 - Math.abs(yDistance))) {
if (data.sfLastYDist < 0.0 || from.isOnGround(0.5 - Math.abs(yDistance))) {
return applyLostGround(player, from, true, data, "step");
}
// else data.stats.addStats(data.stats.getId("sfLostGround_" + "step", true), 0);
}
// Interpolation check.
@ -1096,9 +1099,9 @@ public class SurvivalFly extends Check {
// TODO: Check use of jump-amplifier.
// TODO: Might check fall distance.
// && data.sfJumpPhase > 3 <- Seems to be a problem with cake on a block + jump over both mini edges (...).
if (data.fromX != Double.MAX_VALUE && yDistance > 0 && data.sfLastYDist < 0 && !to.isOnGround()) {
if (data.fromX != Double.MAX_VALUE && yDistance > 0 && data.sfLastYDist < 0.0 && !to.isOnGround()) {
// TODO: Check if last-y-dist or sprinting should be considered.
if (setBackYDistance > 0D && setBackYDistance <= 1.5D + 0.2 * data.jumpAmplifier || setBackYDistance < 0 && Math.abs(setBackYDistance) < 3.0) {
if (setBackYDistance > 0.0 && setBackYDistance <= 1.5D + 0.2 * data.jumpAmplifier || setBackYDistance < 0.0 && Math.abs(setBackYDistance) < 3.0) {
// Interpolate from last to-coordinates to the from
// coordinates (with some safe-guard).
final double dX = from.getX() - data.fromX;
@ -1116,7 +1119,6 @@ public class SurvivalFly extends Check {
if (BlockProperties.isOnGround(from.getBlockCache(), Math.min(data.fromX, from.getX()) - r, iY - yMargin, Math.min(data.fromZ, from.getZ()) - r, Math.max(data.fromX, from.getX()) + r, iY + 0.25, Math.max(data.fromZ, from.getZ()) + r, 0L)) {
return applyLostGround(player, from, true, data, "interpolate");
}
// else data.stats.addStats(data.stats.getId("sfLostGround_" + "interpolate", true), 0);
}
}
}
@ -1151,26 +1153,24 @@ public class SurvivalFly extends Check {
// TODO: <= 7 might work with speed II, not sure with above.
// TODO: account for speed/sprint
// TODO: account for half steps !?
if (from.isOnGround(0.6, 0.4, 0, 0L) ) {
if (from.isOnGround(0.6, 0.4, 0.0, 0L) ) {
// TODO: further narrow down bounds ?
// Temporary "fix".
return applyLostGround(player, from, true, data, "pyramid");
}
// else data.stats.addStats(data.stats.getId("sfLostGround_" + "pyramid", true), 0);
}
// Check for jumping up strange blocks like flower pots on top of other blocks.
if (yDistance == 0 && data.sfLastYDist > 0 && data.sfLastYDist < 0.25 && data.sfJumpPhase <= 6 + data.jumpAmplifier * 3 && setBackYDistance > 1.0 && setBackYDistance < 1.5 + 0.2 * data.jumpAmplifier && !to.isOnGround()) {
if (yDistance == 0.0 && data.sfLastYDist > 0.0 && data.sfLastYDist < 0.25 && data.sfJumpPhase <= 6 + data.jumpAmplifier * 3.0 && setBackYDistance > 1.0 && setBackYDistance < 1.5 + 0.2 * data.jumpAmplifier && !to.isOnGround()) {
// TODO: confine by block types ?
if (from.isOnGround(0.25, 0.4, 0, 0L) ) {
// Temporary "fix".
return applyLostGround(player, from, true, data, "ministep");
}
// else data.stats.addStats(data.stats.getId("sfLostGround_" + "ministep", true), 0);
}
}
// Lost ground while falling onto/over edges of blocks.
if (yDistance < 0 && hDistance <= 0.5 && data.sfLastYDist < 0 && yDistance > data.sfLastYDist && !to.isOnGround()) {
if (yDistance < 0 && hDistance <= 0.5 && data.sfLastYDist < 0.0 && yDistance > data.sfLastYDist && !to.isOnGround()) {
// TODO: Should this be an extra lost-ground(to) check, setting toOnGround [for no-fall no difference]?
// TODO: yDistance <= 0 might be better.
// Also clear accounting data.
@ -1178,7 +1178,6 @@ public class SurvivalFly extends Check {
if (from.isOnGround(0.5, 0.2, 0) || to.isOnGround(0.5, Math.min(0.2, 0.01 + hDistance), Math.min(0.1, 0.01 + -yDistance))) {
return applyLostGround(player, from, true, data, "edge");
}
// else data.stats.addStats(data.stats.getId("sfLostGround_" + "edge", true), 0);
}
// Nothing found.
@ -1213,7 +1212,6 @@ public class SurvivalFly extends Check {
// (Usually yDistance should be -0.078)
return applyLostGround(player, from, true, data, "fastedge");
}
// else data.stats.addStats(data.stats.getId("sfLostGround_" + "fastedge", true), 0);
}
return false;
}
@ -1246,7 +1244,6 @@ public class SurvivalFly extends Check {
// Tell NoFall that we assume the player to have been on ground somehow.
data.noFallAssumeGround = true;
tags.add("lostground_" + tag);
// data.stats.addStats(data.stats.getId("sfLostGround_" + tag, true), 1);
return true;
}
@ -1310,7 +1307,7 @@ public class SurvivalFly extends Check {
if (data.hasSetBack()) {
final Location newTo = data.getSetBack(loc);
data.prepareSetBack(newTo);
player.teleport(newTo);
player.teleport(newTo, TeleportCause.PLUGIN);
}
else{
// Solve by extra actions ? Special case (probably never happens)?
@ -1344,7 +1341,10 @@ public class SurvivalFly extends Check {
}
if (data.sfCobwebVL < 550) { // Totally random !
// Silently set back.
if (!data.hasSetBack()) data.setSetBack(player.getLocation()); // ? check moment of call.
if (!data.hasSetBack()) {
data.setSetBack(player.getLocation(useLoc)); // ? check moment of call.
useLoc.setWorld(null);
}
data.sfJumpPhase = 0;
data.sfLastYDist = data.sfLastHDist = Double.MAX_VALUE;
return true;

View File

@ -30,7 +30,7 @@ public class VehicleSetBack implements Runnable{
final MovingData data = MovingData.getData(player);
data.morePacketsVehicleTaskId = -1;
try{
data.setTeleported(location);
data.prepareSetBack(location);
TeleportUtil.teleport(vehicle, player, location, debug);
}
catch(Throwable t){

View File

@ -24,57 +24,63 @@ public class CommandUtil {
* Return plugin + server commands [Subject to change].
* @return Returns null if not CraftBukkit or CommandMap not available.
*/
public static CommandMap getCommandMap(){
// TODO: compat / null
try{
public static CommandMap getCommandMap() {
try {
return NCPAPIProvider.getNoCheatPlusAPI().getMCAccess().getCommandMap();
}
catch(Throwable t){
catch (Throwable t) {
LogUtil.logSevere(t);
return null;
}
}
/**
* Fails with an exception if SimpleCommandMap is not found, currently.
* Get all Command instances, that NCP can get hold of. Attempt to get a SimpleCommandMap instance from the server to get the actually registered commands, but also get commands from JavaPlugin instances.
* @return
*/
public static Collection<Command> getCommands(){
CommandMap commandMap = getCommandMap();
if (commandMap != null && commandMap instanceof SimpleCommandMap){
return ((SimpleCommandMap) commandMap).getCommands();
public static Collection<Command> getCommands() {
final Collection<Command> commands = new LinkedHashSet<Command>(500);
// All (?) commands from the SimpleCommandMap of the server, if available.
final CommandMap commandMap = getCommandMap();
if (commandMap != null && commandMap instanceof SimpleCommandMap) {
commands.addAll(((SimpleCommandMap) commandMap).getCommands());
}
else{
final Collection<Command> commands = new LinkedHashSet<Command>(100);
for (final Plugin plugin : Bukkit.getPluginManager().getPlugins()){
if (plugin instanceof JavaPlugin){
final JavaPlugin javaPlugin = (JavaPlugin) plugin;
final Map<String, Map<String, Object>> map = javaPlugin.getDescription().getCommands();
if (map != null){
for (String label : map.keySet()){
Command command = javaPlugin.getCommand(label);
if (command != null) commands.add(command);
// TODO: Fall-back for Vanilla / CB commands? [Fall-back should be altering permission defaults, though negating permissions is the right way.]
// Fall-back: plugin commands.
for (final Plugin plugin : Bukkit.getPluginManager().getPlugins()) {
if (plugin instanceof JavaPlugin) {
final JavaPlugin javaPlugin = (JavaPlugin) plugin;
final Map<String, Map<String, Object>> map = javaPlugin.getDescription().getCommands();
if (map != null) {
for (String label : map.keySet()) {
Command command = javaPlugin.getCommand(label);
if (command != null) {
commands.add(command);
}
}
}
}
// TODO: Vanilla / CB commands !?
return commands;
}
return commands;
}
/**
* Get the command label (trim + lower case), include server commands [subject to change].
* @param alias
* @param strict If to return null if no command is found.
* @return
* @return The command label, if possible to find, or the alias itself (+ trim + lower-case).
*/
public static String getCommandLabel(final String alias, final boolean strict){
public static String getCommandLabel(final String alias, final boolean strict) {
final Command command = getCommand(alias);
if (command == null){
if (command == null) {
return strict ? null : alias.trim().toLowerCase();
}
else return command.getLabel().trim().toLowerCase();
else {
return command.getLabel().trim().toLowerCase();
}
}
/**
@ -85,7 +91,7 @@ public class CommandUtil {
public static Command getCommand(final String alias) {
final String lcAlias = alias.trim().toLowerCase();
final CommandMap map = getCommandMap();
if (map != null){
if (map != null) {
return map.getCommand(lcAlias);
} else {
// TODO: maybe match versus plugin commands.
@ -101,18 +107,22 @@ public class CommandUtil {
public static List<String> getCheckTypeTabMatches(final String input) {
final String ref = input.toUpperCase().replace('-', '_').replace('.', '_');
final List<String> res = new ArrayList<String>();
for (final CheckType checkType : CheckType.values()){
for (final CheckType checkType : CheckType.values()) {
final String name = checkType.name();
if (name.startsWith(ref)) res.add(name);
}
if (ref.indexOf('_') == -1){
for (final CheckType checkType : CheckType.values()){
final String name = checkType.name();
final String[] split = name.split("_", 2);
if (split.length > 1 && split[1].startsWith(ref)) res.add(name);
if (name.startsWith(ref)) {
res.add(name);
}
}
if (!res.isEmpty()){
if (ref.indexOf('_') == -1) {
for (final CheckType checkType : CheckType.values()) {
final String name = checkType.name();
final String[] split = name.split("_", 2);
if (split.length > 1 && split[1].startsWith(ref)) {
res.add(name);
}
}
}
if (!res.isEmpty()) {
Collections.sort(res);
return res;
}

View File

@ -22,7 +22,7 @@ import fr.neatmonster.nocheatplus.command.admin.CommandsCommand;
import fr.neatmonster.nocheatplus.command.admin.InfoCommand;
import fr.neatmonster.nocheatplus.command.admin.InspectCommand;
import fr.neatmonster.nocheatplus.command.admin.LagCommand;
import fr.neatmonster.nocheatplus.command.admin.NCPVersionCommand;
import fr.neatmonster.nocheatplus.command.admin.VersionCommand;
import fr.neatmonster.nocheatplus.command.admin.ReloadCommand;
import fr.neatmonster.nocheatplus.command.admin.RemovePlayerCommand;
import fr.neatmonster.nocheatplus.command.admin.exemption.ExemptCommand;
@ -89,7 +89,7 @@ public class NoCheatPlusCommand extends BaseCommand{
new KickCommand(plugin),
new KickListCommand(plugin),
new LagCommand(plugin),
new NCPVersionCommand(plugin),
new VersionCommand(plugin),
new NotifyCommand(plugin),
new ReloadCommand(plugin, notifyReload),
new RemovePlayerCommand(plugin),

View File

@ -1,9 +1,10 @@
package fr.neatmonster.nocheatplus.command.actions;
import java.util.List;
import java.util.UUID;
import org.bukkit.Bukkit;
import org.bukkit.OfflinePlayer;
import org.bukkit.Server;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
@ -14,6 +15,7 @@ import fr.neatmonster.nocheatplus.command.BaseCommand;
import fr.neatmonster.nocheatplus.logging.LogUtil;
import fr.neatmonster.nocheatplus.permissions.Permissions;
import fr.neatmonster.nocheatplus.players.DataManager;
import fr.neatmonster.nocheatplus.utilities.IdUtil;
public class BanCommand extends BaseCommand {
@ -23,32 +25,62 @@ public class BanCommand extends BaseCommand {
@Override
public boolean onCommand(final CommandSender sender, Command command, String label, String[] args) {
// TODO: Consider supporting vanilla syntax or removing this command :p.
// Args contains "ban" as first arg.
if (args.length < 2) return false;
final String name = args[1];
if (args.length < 2) {
return false;
}
final String name = args[1].trim();
final String reason;
if (args.length > 2) reason = AbstractCommand.join(args, 2);
else reason = "";
if (args.length > 2) {
reason = AbstractCommand.join(args, 2);
}
else {
reason = "";
}
ban(sender, name, reason);
return true;
}
/**
*
* @param sender
* @param name Trimmed name.
* @param reason
*/
void ban(CommandSender sender, String name, String reason) {
final Server server = Bukkit.getServer();
Player player = DataManager.getPlayer(name);
// Pro logic below.
if (player == null && !IdUtil.isValidMinecraftUserName(name)) {
UUID id = IdUtil.UUIDFromStringSafe(name);
if (id != null) {
LogUtil.logWarning("Banning by UUID might not work (" + id.toString()+"), relay to the vanilla command.");
} else {
LogUtil.logWarning("Might not be a valid user name: " + name);
}
}
if (player != null){
player.kickPlayer(reason);
}
OfflinePlayer offlinePlayer = Bukkit.getServer().getOfflinePlayer(name);
offlinePlayer.setBanned(true);
LogUtil.logInfo("[NoCheatPlus] (" + sender.getName() + ") Banned " + offlinePlayer.getName() + " : " + reason);
// Relay to the server command for compatibility reasons.
server.dispatchCommand(server.getConsoleSender(), "ban " + name);
logBan(sender, player, name, reason);
}
private void logBan(CommandSender sender, Player player, String name, String reason) {
LogUtil.logInfo("[NoCheatPlus] (" + sender.getName() + ") Banned " + name + (player != null ? ("/" + player.getName()) : "") + " : " + reason);
}
/* (non-Javadoc)
* @see fr.neatmonster.nocheatplus.command.AbstractCommand#onTabComplete(org.bukkit.command.CommandSender, org.bukkit.command.Command, java.lang.String, java.lang.String[])
*/
@Override
public List<String> onTabComplete(CommandSender sender, Command command,
String alias, String[] args) {
public List<String> onTabComplete(CommandSender sender, Command command, String alias, String[] args) {
// TODO: Consider adding player names and other.
return null;
}

View File

@ -13,6 +13,7 @@ import org.bukkit.plugin.java.JavaPlugin;
import org.bukkit.potion.PotionEffect;
import fr.neatmonster.nocheatplus.command.BaseCommand;
import fr.neatmonster.nocheatplus.compat.BridgeHealth;
import fr.neatmonster.nocheatplus.permissions.Permissions;
import fr.neatmonster.nocheatplus.players.DataManager;
@ -53,7 +54,7 @@ public class InspectCommand extends BaseCommand {
builder.append(" (" + (player.isOnline() ? "online" : "offline") + (player.isDead() ? ",dead" : "") + (player.isValid() ? "" : ",invalid") + (player.isInsideVehicle() ? (",vehicle=" + player.getVehicle().getType() + "@" + locString(player.getVehicle().getLocation())) : "")+ "):");
// TODO: isValid, isDead, isInsideVehicle ...
// Health.
builder.append(" health=" + f1.format(player.getHealth()) + "/" + f1.format(player.getMaxHealth()));
builder.append(" health=" + f1.format(BridgeHealth.getHealth(player)) + "/" + f1.format(BridgeHealth.getMaxHealth(player)));
// Food.
builder.append(" food=" + player.getFoodLevel());
// Exp.

Some files were not shown because too many files have changed in this diff Show More