From 5bf347ca886f27b8ee6b005cdc9392d453e1eab7 Mon Sep 17 00:00:00 2001 From: asofold Date: Mon, 8 Oct 2012 04:56:53 +0200 Subject: [PATCH] Add ability to use a cache for block id and data for PlayerLocation. --- .../nocheatplus/utilities/PlayerLocation.java | 58 ++++++-- .../nocheatplus/utilities/TypeIdCache.java | 136 ++++++++++++++++++ 2 files changed, 181 insertions(+), 13 deletions(-) create mode 100644 src/fr/neatmonster/nocheatplus/utilities/TypeIdCache.java diff --git a/src/fr/neatmonster/nocheatplus/utilities/PlayerLocation.java b/src/fr/neatmonster/nocheatplus/utilities/PlayerLocation.java index 869822ae..8bb14ae6 100644 --- a/src/fr/neatmonster/nocheatplus/utilities/PlayerLocation.java +++ b/src/fr/neatmonster/nocheatplus/utilities/PlayerLocation.java @@ -86,6 +86,8 @@ public class PlayerLocation { /** The worldServer. */ private WorldServer worldServer; + + private TypeIdCache idCache; /** * Gets the location. @@ -215,7 +217,7 @@ public class PlayerLocation { .floor(boundingBox.e - 0.001D); blockY++) for (int blockZ = (int) Math.floor(boundingBox.c + 0.001D); blockZ <= (int) Math .floor(boundingBox.f - 0.001D); blockZ++) - if (worldServer.getTypeId(blockX, blockY, blockZ) == Material.WEB.getId()) + if (getTypeId(blockX, blockY, blockZ) == Material.WEB.getId()) inWeb = true; if (inWeb == null) inWeb = false; @@ -254,7 +256,7 @@ public class PlayerLocation { public boolean isOnIce() { if (onIce == null) if (entity.getBukkitEntity().isSneaking() || entity.getBukkitEntity().isBlocking()) - onIce = worldServer.getTypeId(blockX, (int) Math.floor(boundingBox.b - 0.1D), blockZ) == Material.ICE.getId(); + onIce = getTypeId(blockX, (int) Math.floor(boundingBox.b - 0.1D), blockZ) == Material.ICE.getId(); else onIce = getTypeIdBelow() == Material.ICE.getId(); return onIce; @@ -336,18 +338,18 @@ public class PlayerLocation { } public Integer getTypeId() { - if (typeId == null) typeId = worldServer.getTypeId(blockX, blockY, blockZ); + if (typeId == null) typeId = getTypeId(blockX, blockY, blockZ); return typeId; } public Integer getTypeIdBelow() { - if (typeIdBelow == null) typeIdBelow = worldServer.getTypeId(blockX, blockY - 1, blockZ); + if (typeIdBelow == null) typeIdBelow = getTypeId(blockX, blockY - 1, blockZ); return typeIdBelow; } public Integer getData(){ - if (data == null) data = worldServer.getData(blockX, blockY, blockZ); + if (data == null) data = getData(blockX, blockY, blockZ); return data; } @@ -358,36 +360,36 @@ public class PlayerLocation { if ((fromData & 0x8) == 0){ // not falling. if ((xDistance > 0)){ - if (fromData < 7 && BlockProperties.isLiquid(worldServer.getTypeId(blockX + 1, blockY, blockZ)) && worldServer.getData(blockX + 1, blockY, blockZ) > fromData){ + if (fromData < 7 && BlockProperties.isLiquid(getTypeId(blockX + 1, blockY, blockZ)) && getData(blockX + 1, blockY, blockZ) > fromData){ return true; } - else if (fromData > 0 && BlockProperties.isLiquid(worldServer.getTypeId(blockX - 1, blockY, blockZ)) && worldServer.getData(blockX - 1, blockY, blockZ) < fromData){ + else if (fromData > 0 && BlockProperties.isLiquid(getTypeId(blockX - 1, blockY, blockZ)) && getData(blockX - 1, blockY, blockZ) < fromData){ // reverse direction. return true; } } else if (xDistance < 0){ - if (fromData < 7 && BlockProperties.isLiquid(worldServer.getTypeId(blockX - 1, blockY, blockZ)) && worldServer.getData(blockX - 1, blockY, blockZ) > fromData){ + if (fromData < 7 && BlockProperties.isLiquid(getTypeId(blockX - 1, blockY, blockZ)) && getData(blockX - 1, blockY, blockZ) > fromData){ return true; } - else if (fromData > 0 && BlockProperties.isLiquid(worldServer.getTypeId(blockX + 1, blockY, blockZ)) && worldServer.getData(blockX + 1, blockY, blockZ) < fromData){ + else if (fromData > 0 && BlockProperties.isLiquid(getTypeId(blockX + 1, blockY, blockZ)) && getData(blockX + 1, blockY, blockZ) < fromData){ // reverse direction. return true; } } if (zDistance > 0){ - if (fromData < 7 && BlockProperties.isLiquid(worldServer.getTypeId(blockX, blockY, blockZ + 1)) && worldServer.getData(blockX, blockY, blockZ + 1) > fromData){ + if (fromData < 7 && BlockProperties.isLiquid(getTypeId(blockX, blockY, blockZ + 1)) && getData(blockX, blockY, blockZ + 1) > fromData){ return true; } - else if (fromData > 0 && BlockProperties.isLiquid(worldServer.getTypeId(blockX , blockY, blockZ - 1)) && worldServer.getData(blockX, blockY, blockZ - 1) < fromData){ + else if (fromData > 0 && BlockProperties.isLiquid(getTypeId(blockX , blockY, blockZ - 1)) && getData(blockX, blockY, blockZ - 1) < fromData){ // reverse direction. return true; } } else if (zDistance < 0 ){ - if (fromData < 7 && BlockProperties.isLiquid(worldServer.getTypeId(blockX, blockY, blockZ - 1)) && worldServer.getData(blockX, blockY, blockZ - 1) > fromData){ + if (fromData < 7 && BlockProperties.isLiquid(getTypeId(blockX, blockY, blockZ - 1)) && getData(blockX, blockY, blockZ - 1) > fromData){ return true; } - else if (fromData > 0 && BlockProperties.isLiquid(worldServer.getTypeId(blockX , blockY, blockZ + 1)) && worldServer.getData(blockX, blockY, blockZ + 1) < fromData){ + else if (fromData > 0 && BlockProperties.isLiquid(getTypeId(blockX , blockY, blockZ + 1)) && getData(blockX, blockY, blockZ + 1) < fromData){ // reverse direction. return true; } @@ -400,7 +402,29 @@ public class PlayerLocation { // Maybe make block coordinate fields later. return blockX == other.getBlockX() && blockZ == other.getBlockZ() && blockY == other.getBlockY(); } + + /** + * Uses id cache if present. + * @param x + * @param y + * @param z + * @return + */ + public final int getTypeId(final int x, final int y, final int z){ + return idCache == null ? worldServer.getTypeId(x, y, z) : idCache.getTypeId(x, y, z); + } + /** + * Uses id cache if present. + * @param x + * @param y + * @param z + * @return + */ + public final int getData(final int x, final int y, final int z){ + return idCache == null ? worldServer.getData(x, y, z) : idCache.getData(x, y, z); + } + /** * TODO: temp maybe * @return @@ -409,6 +433,14 @@ public class PlayerLocation { return worldServer; } + /** + * Set the id cache for faster id getting. + * @param cache + */ + public void setIdCache(final TypeIdCache cache) { + this.idCache = cache; + } + /** * Set some references to null. */ diff --git a/src/fr/neatmonster/nocheatplus/utilities/TypeIdCache.java b/src/fr/neatmonster/nocheatplus/utilities/TypeIdCache.java new file mode 100644 index 00000000..a1e47a16 --- /dev/null +++ b/src/fr/neatmonster/nocheatplus/utilities/TypeIdCache.java @@ -0,0 +1,136 @@ +package fr.neatmonster.nocheatplus.utilities; + +import java.util.HashMap; +import java.util.Map; + +import net.minecraft.server.IBlockAccess; + +import org.bukkit.World; +import org.bukkit.craftbukkit.CraftWorld; + +/** + * Access to type-ids using caching techniques. + * @author mc_dev + * + */ +public class TypeIdCache { + /** + * TODO: Make a map for faster queries (without object creation). + * TODO: Not sure the prime numbers are too big for normal use. + * @author mc_dev + * + */ + private static class Pos3D{ + private static final int p1 = 73856093; + private static final int p2 = 19349663; + private static final int p3 = 83492791; + // Cube coordinates: + public final int x; + public final int y; + public final int z; + public final int hash; + /** + * + * @param x + * @param y + * @param z + * @param size + */ + public Pos3D (final int x, final int y, final int z){ + // Cube related coordinates: + this.x = x; + this.y = y; + this.z = z; + // Hash + hash = getHash(this.x, this.y, this.z); + } + + @Override + public final boolean equals(final Object obj) { + if (obj instanceof Pos3D){ + final Pos3D other = (Pos3D) obj; + return other.x == x && other.y == y && other.z == z; + } + else return false; + } + + @Override + public final int hashCode() { + return hash; + } + + public static final int getHash(final int x, final int y, final int z) { + return p1 * x ^ p2 * y ^ p3 * z; + } + } + + /** + * For getting ids. + */ + private IBlockAccess access = null; + /** Cached type-ids. */ + private final Map idMap = new HashMap(); + /** Cahced data values. */ + private final Map dataMap = new HashMap(); + + // TODO: maybe make very fast access arrays for the ray tracing checks. +// private int[] id = null; +// private int[] data = null; + + public TypeIdCache(){ + } + + public TypeIdCache(final World world){ + setAccess(world); + } + + public TypeIdCache(final IBlockAccess access){ + setAccess(access); + } + + /** + * Does not do cleanup. + * @param world + */ + public void setAccess(final World world){ + setAccess(((CraftWorld) world).getHandle()); + } + + /** + * Does not do cleanup. + * @param access + */ + public void setAccess(final IBlockAccess access){ + this.access = access; + } + + /** + * Remove references. + */ + public void cleanup(){ + access = null; + idMap.clear(); + dataMap.clear(); + } + + + public Integer 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; + final Integer nId = access.getTypeId(x, y, z); + idMap.put(pos, nId); + return nId; + } + + public Integer 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; + final Integer nData = access.getData(x, y, z); + dataMap.put(pos, nData); + return nData; + } + + +}