From c9427d4ff1006b2ce2e06cdf99405a85ee626364 Mon Sep 17 00:00:00 2001 From: asofold Date: Mon, 8 Oct 2012 17:50:27 +0200 Subject: [PATCH] Add Methods for bounding box tests. PlayerLocation: Use idCache for more, return idCache as IBlockAccess if present. [DEBUG, Ongoing] --- .../checks/moving/MovingListener.java | 2 +- .../utilities/BlockProperties.java | 15 ++- .../nocheatplus/utilities/PlayerLocation.java | 81 ++++++++---- .../nocheatplus/utilities/TypeIdCache.java | 123 +++++++++++++++++- 4 files changed, 189 insertions(+), 32 deletions(-) diff --git a/src/fr/neatmonster/nocheatplus/checks/moving/MovingListener.java b/src/fr/neatmonster/nocheatplus/checks/moving/MovingListener.java index 4fe90d31..33db9fc7 100644 --- a/src/fr/neatmonster/nocheatplus/checks/moving/MovingListener.java +++ b/src/fr/neatmonster/nocheatplus/checks/moving/MovingListener.java @@ -70,7 +70,7 @@ public class MovingListener implements Listener { public final void set(final Player player, final Location from, final Location to, final double yOnGround){ this.from.set(from, player, yOnGround); this.to.set(to, player, yOnGround); - this.cache.setAccess(this.from.getBlockAccess()); + this.cache.setAccess(this.from.getWorldServer()); this.from.setIdCache(cache); this.to.setIdCache(cache); } diff --git a/src/fr/neatmonster/nocheatplus/utilities/BlockProperties.java b/src/fr/neatmonster/nocheatplus/utilities/BlockProperties.java index 32281ab9..8fa33f27 100644 --- a/src/fr/neatmonster/nocheatplus/utilities/BlockProperties.java +++ b/src/fr/neatmonster/nocheatplus/utilities/BlockProperties.java @@ -247,6 +247,8 @@ public class BlockProperties { public static final int F_LIQUID = 0x2; public static final int F_SOLID = 0x4; public static final int F_IGN_PASSABLE = 0x8; + public static final int F_WATER = 0x10; + public static final int F_LAVA = 0x20; static{ init(); @@ -314,13 +316,20 @@ public class BlockProperties { Material.WOOD_STAIRS, Material.SPRUCE_WOOD_STAIRS, Material.BIRCH_WOOD_STAIRS, Material.JUNGLE_WOOD_STAIRS}){ blockFlags[mat.getId()] |= F_STAIRS; } - // Liquid. + // WATER. for (final Material mat : new Material[]{ - Material.LAVA, Material.STATIONARY_LAVA, Material.STATIONARY_WATER, Material.WATER, }) { - blockFlags[mat.getId()] |= F_LIQUID; // TODO: This might already be handled above now. + blockFlags[mat.getId()] |= F_LIQUID | F_WATER; } + // LAVA. + for (final Material mat : new Material[]{ + Material.LAVA, Material.STATIONARY_LAVA, + }) { + blockFlags[mat.getId()] |= F_LIQUID | F_LAVA; + } + // Workarounds. + blockFlags[Material.WATER_LILY.getId()] |= F_SOLID; // Ignore for passable. for (final Material mat : new Material[]{ Material.WOOD_PLATE, Material.STONE_PLATE, diff --git a/src/fr/neatmonster/nocheatplus/utilities/PlayerLocation.java b/src/fr/neatmonster/nocheatplus/utilities/PlayerLocation.java index 12c337e8..5790e78e 100644 --- a/src/fr/neatmonster/nocheatplus/utilities/PlayerLocation.java +++ b/src/fr/neatmonster/nocheatplus/utilities/PlayerLocation.java @@ -175,20 +175,16 @@ public class PlayerLocation { if (inLava == null) { AxisAlignedBB boundingBoxLava = boundingBox.clone(); boundingBoxLava = boundingBoxLava.grow(-0.10000000149011612D, -0.40000000596046448D, -0.10000000149011612D); - inLava = worldServer.a(boundingBoxLava, net.minecraft.server.Material.LAVA); + inLava = idCache.collides(boundingBoxLava, BlockProperties.F_LAVA); +// inLava = worldServer.a(boundingBoxLava, net.minecraft.server.Material.LAVA); +// if (inLava.booleanValue() != idCache.collides(boundingBoxLava, BlockProperties.F_LAVA)){ +// System.out.println("INCONSISTENCY IN LAVA (" + inWater + ")."); // TODO: remove +// System.out.println("("+ x +"," + y + "," + z + ":"+ getTypeId() + ")"); +// } } return inLava; } - - /** - * Checks if the player is in a liquid. - * - * @return true, if the player is in a liquid - */ - public boolean isInLiquid() { - return isInLava() || isInWater(); - } - + /** * Checks if the player is in water. * @@ -199,25 +195,45 @@ public class PlayerLocation { AxisAlignedBB boundingBoxWater = boundingBox.clone(); boundingBoxWater = boundingBoxWater.grow(0.0D, -0.40000000596046448D, 0.0D); boundingBoxWater = boundingBoxWater.shrink(0.001D, 0.001D, 0.001D); - inWater = worldServer.a(boundingBoxWater, net.minecraft.server.Material.WATER, entity); + inWater = idCache.collides(boundingBoxWater, BlockProperties.F_WATER); +// inWater = worldServer.a(boundingBoxWater, net.minecraft.server.Material.WATER, entity); +// if (inWater.booleanValue() != idCache.collides(boundingBoxWater, BlockProperties.F_WATER)){ +// System.out.println("INCONSISTENCY IN WATER (" + inWater + ")."); // TODO: remove +// System.out.println("("+ x +"," + y + "," + z + ":"+ getTypeId() + ")"); +// } } return inWater; } + /** + * Checks if the player is in a liquid. + * + * @return true, if the player is in a liquid + */ + public boolean isInLiquid() { + // TODO: optimize (check liquid first and only if liquid check further) + return isInLava() || isInWater(); + } + /** * Checks if the player is in web. * * @return true, if the player is in web */ public boolean isInWeb() { + final int webId = Material.WEB.getId(); if (inWeb == null) { - for (int blockX = Location.locToBlock(boundingBox.a + 0.001D); blockX <= Location.locToBlock(boundingBox.d - 0.001D); blockX++) - for (int blockY = Location.locToBlock(boundingBox.b + 0.001D); blockY <= Location.locToBlock(boundingBox.e - 0.001D); blockY++) - for (int blockZ = Location.locToBlock(boundingBox.c + 0.001D); blockZ <= Location.locToBlock(boundingBox.f - 0.001D); blockZ++) - if (getTypeId(blockX, blockY, blockZ) == Material.WEB.getId()) + for (int blockX = Location.locToBlock(boundingBox.a + 0.001D); blockX <= Location.locToBlock(boundingBox.d - 0.001D); blockX++){ + for (int blockY = Location.locToBlock(boundingBox.b + 0.001D); blockY <= Location.locToBlock(boundingBox.e - 0.001D); blockY++){ + for (int blockZ = Location.locToBlock(boundingBox.c + 0.001D); blockZ <= Location.locToBlock(boundingBox.f - 0.001D); blockZ++){ + if (getTypeId(blockX, blockY, blockZ) == webId){ inWeb = true; - if (inWeb == null) - inWeb = false; + break; + } + } + } + } + inWeb = false; } return inWeb; } @@ -231,7 +247,13 @@ public class PlayerLocation { if (onGround == null) { AxisAlignedBB boundingBoxGround = boundingBox.clone(); boundingBoxGround = boundingBoxGround.d(0D, -getyOnGround(), 0D); - onGround = worldServer.getCubes(entity, boundingBoxGround).size() > 0; + onGround = idCache.collides(boundingBoxGround, BlockProperties.F_SOLID); +// onGround = worldServer.getCubes(entity, boundingBoxGround).size() > 0; +// if (onGround.booleanValue() != idCache.collides(boundingBoxGround, BlockProperties.F_SOLID)){ +// System.out.println("INCONSISTENCY ON GROUND (" + onGround + ")."); // TODO: remove +// System.out.println("("+ x +"," + y + "," + z + ":"+ getTypeId() + ")"); +// } + // TODO: Check for entities (boats etc.) } return onGround; } @@ -242,11 +264,13 @@ public class PlayerLocation { * @return true, if the player is on ice */ public boolean isOnIce() { - if (onIce == null) - if (entity.getBukkitEntity().isSneaking() || entity.getBukkitEntity().isBlocking()) + if (onIce == null){ + final org.bukkit.entity.Player entity = this.entity.getBukkitEntity(); + if (entity.isSneaking() || entity.isBlocking()) onIce = getTypeId(blockX, Location.locToBlock(boundingBox.b - 0.1D), blockZ) == Material.ICE.getId(); else - onIce = getTypeIdBelow() == Material.ICE.getId(); + onIce = getTypeIdBelow().intValue() == Material.ICE.getId(); + } return onIce; } @@ -287,7 +311,7 @@ public class PlayerLocation { } /** - * Sets the player location object. + * Sets the player location object. Does not set or reset idCache. * * @param location * the location @@ -313,6 +337,8 @@ public class PlayerLocation { typeId = typeIdBelow = null; aboveStairs = inLava = inWater = inWeb = onGround = onIce = onLadder = null; + // TODO: consider idCache.setAccess. + this.setyOnGround(yFreedom); } @@ -414,11 +440,11 @@ public class PlayerLocation { } /** - * TODO: temp maybe + * * @return */ public final IBlockAccess getBlockAccess() { - return worldServer; + return idCache == null ? worldServer : idCache; } /** @@ -437,6 +463,11 @@ public class PlayerLocation { world = null; worldServer = null; boundingBox = null; + idCache = null; } + public WorldServer getWorldServer() { + return worldServer; + } + } diff --git a/src/fr/neatmonster/nocheatplus/utilities/TypeIdCache.java b/src/fr/neatmonster/nocheatplus/utilities/TypeIdCache.java index a1e47a16..04cc9f03 100644 --- a/src/fr/neatmonster/nocheatplus/utilities/TypeIdCache.java +++ b/src/fr/neatmonster/nocheatplus/utilities/TypeIdCache.java @@ -3,8 +3,13 @@ package fr.neatmonster.nocheatplus.utilities; import java.util.HashMap; import java.util.Map; +import net.minecraft.server.AxisAlignedBB; +import net.minecraft.server.Block; import net.minecraft.server.IBlockAccess; +import net.minecraft.server.Material; +import net.minecraft.server.TileEntity; +import org.bukkit.Location; import org.bukkit.World; import org.bukkit.craftbukkit.CraftWorld; @@ -13,7 +18,7 @@ import org.bukkit.craftbukkit.CraftWorld; * @author mc_dev * */ -public class TypeIdCache { +public class TypeIdCache implements IBlockAccess{ /** * TODO: Make a map for faster queries (without object creation). * TODO: Not sure the prime numbers are too big for normal use. @@ -114,7 +119,7 @@ public class TypeIdCache { } - public Integer getTypeId(final int x, final int y, final int z){ + public int getTypeId(final int x, final int y, final int z){ final Pos3D pos = new Pos3D(x, y, z); final Integer pId = idMap.get(pos); if (pId != null) return pId; @@ -123,7 +128,7 @@ public class TypeIdCache { return nId; } - public Integer getData(final int x, final int y, final int z){ + public int getData(final int x, final int y, final int z){ final Pos3D pos = new Pos3D(x, y, z); final Integer pData = dataMap.get(pos); if (pData != null) return pData; @@ -132,5 +137,117 @@ public class TypeIdCache { return nData; } + /** + * + * @param box + * @param flags Block flags (@see fr.neatmonster.nocheatplus.utilities.BlockProperties). + * @return If any block has the flags. + */ + public final boolean hasAnyFlags(final AxisAlignedBB box, final long flags){ + return hasAnyFlags(box.a, box.b, box.c, box.d, box.e, box.f, flags); + } + + /** + * + * @param minX + * @param minY + * @param minZ + * @param maxX + * @param maxY + * @param maxZ + * @param flags Block flags (@see fr.neatmonster.nocheatplus.utilities.BlockProperties). + * @return If any block has the flags. + */ + public final boolean hasAnyFlags(final double minX, double minY, final double minZ, final double maxX, final double maxY, final double maxZ, final long flags){ + return hasAnyFlags(Location.locToBlock(minX), Location.locToBlock(minY), Location.locToBlock(minZ), Location.locToBlock(maxX), Location.locToBlock(maxY), Location.locToBlock(maxZ), flags); + } + + + /** + * + * @param minX + * @param minY + * @param minZ + * @param maxX + * @param maxY + * @param maxZ + * @param flags Block flags (@see fr.neatmonster.nocheatplus.utilities.BlockProperties). + * @return If any block has the flags. + */ + public final boolean hasAnyFlags(final int minX, int minY, final int minZ, final int maxX, final int maxY, final int maxZ, final long flags){ + for (int x = minX; x <= maxX; x++){ + for (int z = minZ; z <= maxZ; z++){ + for (int y = minY; y <= maxY; y++){ + if ((BlockProperties.getBLockFlags(getTypeId(x, y, z)) & flags) != 0) return true; + } + } + } + return false; + } + + /** + * Test if the box collide with any block that matches the flags somehow. + * @param box + * @param flags + * @return + */ + public final boolean collides(final AxisAlignedBB box, final long flags){ + return collides(box.a, box.b, box.c, box.d, box.e, box.f, flags); + } + + /** + * Test if the box collide with any block that matches the flags somehow. + * @param minX + * @param minY + * @param minZ + * @param maxX + * @param maxY + * @param maxZ + * @param flags + * @return + */ + public final boolean collides(final double minX, double minY, final double minZ, final double maxX, final double maxY, final double maxZ, final long flags){ + for (int x = Location.locToBlock(minX); x <= Location.locToBlock(maxX); x++){ + for (int z = Location.locToBlock(minZ); z <= Location.locToBlock(maxZ); z++){ + for (int y = Location.locToBlock(minY); y <= Location.locToBlock(maxY); y++){ + final int id = getTypeId(x, y, z); + if ((BlockProperties.getBLockFlags(id) & flags) != 0){ + // Might collide. + final Block block = Block.byId[id]; + block.updateShape(this, x, y, z); + if (minX > block.maxX + x || maxX < block.minX + x) continue; + else if (minY > block.maxY + y || maxY < block.minY + y) continue; + else if (minZ > block.maxZ + z || maxZ < block.minZ + z) continue; + return true; + } + } + } + } + return false; + } + + /** + * Not Optimized. + */ + @Override + public Material getMaterial(int arg0, int arg1, int arg2) { + return access.getMaterial(arg0, arg1, arg2); + } + + /** + * Not optimized. + */ + @Override + public TileEntity getTileEntity(int arg0, int arg1, int arg2) { + return access.getTileEntity(arg0, arg1, arg2); + } + + /** + * Not optimized. + */ + @Override + public boolean s(int arg0, int arg1, int arg2) { + return access.s(arg0, arg1, arg2); + } }