package com.skcraft.playblock.util; import net.minecraft.client.Minecraft; import net.minecraft.client.entity.EntityClientPlayerMP; import net.minecraft.nbt.NBTTagCompound; import com.sk89q.forge.AbstractBehavior; /** * Manages subscribing clients to a resource based on their distance away. */ public class DoubleThresholdRange extends AbstractBehavior { private static final int MAX_RANGE = 64; private static final int MIN_BUFFER_RANGE = 5; private float triggerRange = 0; private float fadeRange = MIN_BUFFER_RANGE; public DoubleThresholdRange() { } /** * Gets the range (in blocks) at which the player will activate and start * playing. * * @see #getTriggerRangeSq() get the squared version, which is faster * @return the range in blocks */ public float getTriggerRange() { return Math.round(Math.sqrt(triggerRange) * 100 / 100); } /** * Gets the range (in blocks) at which the player will activate and start * playing. * * @return the range in blocks, squared */ public float getTriggerRangeSq() { return triggerRange; } /** * Sets the range (in blocks) at which the player will activate and start * playing. * * @param range * the range in blocks */ public void setTriggerRange(float range) { float v = MathUtils.clamp(range, 1, MAX_RANGE); triggerRange = v * v; // Store values squared ensureProperBuffer(); } /** * Gets the range (in blocks) at which the player will stop playing if it is * currently playing. * * @see #getFadeRangeSq() get the squared version, which is faster * @return the range */ public float getFadeRange() { return Math.round(Math.sqrt(fadeRange) * 100 / 100); } /** * Gets the range (in blocks) at which the player will stop playing if it is * currently playing. * * @return the range in blocks, squared */ public float getFadeRangeSq() { return fadeRange; } /** * Sets the range (in blocks) at which the player will stop playing if it is * currently playing. * * @param range * range in blocks, squared */ public void setFadeRange(float range) { float v = MathUtils.clamp(range, 1, MAX_RANGE + MIN_BUFFER_RANGE); fadeRange = v * v; // Store values squared ensureProperBuffer(); } /** * This changes the fade distance appropriately to ensure that there is at * least a {@value #MIN_BUFFER_RANGE} block distance difference between the * trigger distance and the fade distance. */ private void ensureProperBuffer() { float min = getTriggerRange() + MIN_BUFFER_RANGE; if (getFadeRange() < min) { // Do not call setFadeRange()! fadeRange = min * min; // Store values squared } } /** * Return whether the distance given is within the trigger range. * * @param distance * the distance (squared) * @return true if within range */ public boolean inTriggerRangeSq(double distance) { return distance <= getTriggerRangeSq(); } /** * Return whether the distance given is within the fade range (the distance * is greater than the fade range). * * @param distance * the distance (squared) * @return true if within range */ public boolean inFadeRangeSq(double distance) { return distance >= getFadeRangeSq(); } /** * Create a local player range test. * * @return the test */ public RangeTest createRangeTest() { return new RangeTest(); } /** * Write NBT data that needs to be saved to the world. * * @param tag * the tag */ @Override public void writeSaveNBT(NBTTagCompound tag) { tag.setFloat("triggerRange", getTriggerRange()); tag.setFloat("fadeRange", getFadeRange()); } /** * Read NBT data that has been retrieved from a saved world. * * @param tag * the tag */ @Override public void readSaveNBT(NBTTagCompound tag) { setTriggerRange(tag.getFloat("triggerRange")); setFadeRange(tag.getFloat("fadeRange")); } @Override public void writeNetworkedNBT(NBTTagCompound tag) { tag.setFloat("triggerRange", getTriggerRange()); tag.setFloat("fadeRange", getFadeRange()); } @Override public void readNetworkedNBT(NBTTagCompound tag) { if (tag.hasKey("triggerRange")) { setTriggerRange(tag.getFloat("triggerRange")); setFadeRange(tag.getFloat("fadeRange")); } } public class RangeTest { private int lastX = Integer.MAX_VALUE; private int lastY = Integer.MAX_VALUE; private int lastZ = Integer.MAX_VALUE; private boolean withinRange = false; private RangeTest() { } public boolean inRange(double x, double y, double z) { EntityClientPlayerMP player = Minecraft.getMinecraft().thePlayer; if (player.posX != lastX || player.posY != lastY || player.posZ != lastZ) { double distance = player.getDistanceSq(x, y, z); if (!withinRange && inTriggerRangeSq(distance)) { withinRange = true; return true; } else if (withinRange && inFadeRangeSq(distance)) { withinRange = false; return false; } } return withinRange; } public boolean getCachedInRange() { return withinRange; } } }