Improved PlayerLocation objects management. Cleaned up the exemption

API.
This commit is contained in:
NeatMonster 2012-08-25 12:20:28 +02:00
parent 5625b61b41
commit 2d5850a547
12 changed files with 429 additions and 485 deletions

View File

@ -190,12 +190,12 @@ public abstract class Check {
* @return true, if the check is enabled
*/
public boolean isEnabled(final Player player) {
if (NCPExemptionManager.isExempted(player, type)) return false;
try {
return type.isEnabled(player) && !player.hasPermission(type.getPermission());
if (!type.isEnabled(player) || player.hasPermission(type.getPermission()))
return false;
} catch (final Exception e) {
e.printStackTrace();
}
return false;
return !NCPExemptionManager.isExempted(player, type);
}
}

View File

@ -44,7 +44,7 @@ public class Color extends Check {
return message;
final ChatConfig cc = ChatConfig.getConfig(player);
if (!isMainThread && (NCPExemptionManager.isExempted(player, type) || !cc.isEnabled(type)))
if (!isMainThread && (!cc.isEnabled(type) || NCPExemptionManager.isExempted(player, type)))
// Leave out the permission check.
return message;

View File

@ -71,7 +71,7 @@ public class NoPwnage extends Check {
final ChatConfig cc = ChatConfig.getConfig(player);
final ChatData data = ChatData.getData(player);
if (!isMainThread && (NCPExemptionManager.isExempted(player, type) || !cc.isEnabled(type)))
if (!isMainThread && (!cc.isEnabled(type) || NCPExemptionManager.isExempted(player, type)))
return false;
// Keep related to ChatData/NoPwnage/Color used lock.

View File

@ -43,7 +43,8 @@ public class Critical extends Check {
boolean cancel = false;
// We'll need the PlayerLocation to know some important stuff.
final PlayerLocation location = new PlayerLocation(player.getLocation(), player);
PlayerLocation location = new PlayerLocation();
location.set(player.getLocation(), player);
// Check if the hit was a critical hit (positive fall distance, entity in the air, not on ladder, not in liquid
// and without blindness effect).
@ -70,6 +71,8 @@ public class Critical extends Check {
cancel = executeActions(player, data.criticalVL, delta, cc.criticalActions);
}
location = null;
return cancel;
}
}

View File

@ -163,7 +163,8 @@ public class CreativeFly extends Check {
else if (wildcard == ParameterName.LOCATION_TO)
return String.format(Locale.US, "%.2f, %.2f, %.2f", data.to.getX(), data.to.getY(), data.to.getZ());
else if (wildcard == ParameterName.DISTANCE)
return String.format(Locale.US, "%.2f", data.to.subtract(data.from).lengthSquared());
return String.format(Locale.US, "%.2f", data.to.getLocation().subtract(data.from.getLocation())
.lengthSquared());
else
return super.getParameter(wildcard, violationData);
}

View File

@ -8,6 +8,7 @@ import org.bukkit.entity.Player;
import fr.neatmonster.nocheatplus.checks.CheckData;
import fr.neatmonster.nocheatplus.checks.CheckDataFactory;
import fr.neatmonster.nocheatplus.utilities.PlayerLocation;
/*
* M"""""`'"""`YM oo M""""""'YMM dP
@ -49,54 +50,54 @@ public class MovingData implements CheckData {
}
// Violation levels.
public double creativeFlyVL = 0D;
public double morePacketsVL = 0D;
public double morePacketsVehicleVL = 0D;
public double noFallVL = 0D;
public double survivalFlyVL = 0D;
public double creativeFlyVL = 0D;
public double morePacketsVL = 0D;
public double morePacketsVehicleVL = 0D;
public double noFallVL = 0D;
public double survivalFlyVL = 0D;
// Data shared between the fly checks.
public int bunnyhopDelay;
public double horizontalBuffer;
public double horizontalFreedom;
public double horizontalVelocityCounter;
public double jumpAmplifier;
public double verticalFreedom;
public double verticalVelocity;
public int verticalVelocityCounter;
public int bunnyhopDelay;
public double horizontalBuffer;
public double horizontalFreedom;
public double horizontalVelocityCounter;
public double jumpAmplifier;
public double verticalFreedom;
public double verticalVelocity;
public int verticalVelocityCounter;
// Data of the creative check.
public boolean creativeFlyPreviousRefused;
public boolean creativeFlyPreviousRefused;
// Data of the more packets check.
public int morePacketsBuffer = 50;
public long morePacketsLastTime;
public int morePacketsPackets;
public Location morePacketsSetback;
public int morePacketsBuffer = 50;
public long morePacketsLastTime;
public int morePacketsPackets;
public Location morePacketsSetback;
// Data of the more packets vehicle check.
public int morePacketsVehicleBuffer = 50;
public long morePacketsVehicleLastTime;
public int morePacketsVehiclePackets;
public Location morePacketsVehicleSetback;
public int morePacketsVehicleBuffer = 50;
public long morePacketsVehicleLastTime;
public int morePacketsVehiclePackets;
public Location morePacketsVehicleSetback;
// Data of the no fall check.
public double noFallFallDistance;
public boolean noFallOnGround;
public boolean noFallWasOnGround;
public double noFallFallDistance;
public boolean noFallOnGround;
public boolean noFallWasOnGround;
// Data of the survival fly check.
public int survivalFlyJumpPhase;
public double survivalFlyLastFromY;
public int survivalFlyOnIce;
public boolean survivalFlyWasInBed;
public int survivalFlyJumpPhase;
public double survivalFlyLastFromY;
public int survivalFlyOnIce;
public boolean survivalFlyWasInBed;
// Locations shared between all checks.
public Location from;
public Location ground;
public Location setBack;
public Location teleported;
public Location to;
public PlayerLocation from = new PlayerLocation();
public Location ground;
public Location setBack;
public Location teleported;
public PlayerLocation to = new PlayerLocation();
/**
* Clear the data of the fly checks.

View File

@ -29,7 +29,6 @@ import org.bukkit.util.Vector;
import fr.neatmonster.nocheatplus.NoCheatPlus;
import fr.neatmonster.nocheatplus.players.Permissions;
import fr.neatmonster.nocheatplus.utilities.PlayerLocation;
/*
* M"""""`'"""`YM oo
@ -330,31 +329,29 @@ public class MovingListener implements Listener {
// Counter has run out, now reduce the vertical freedom over time.
data.verticalFreedom *= 0.93D;
final PlayerLocation from = new PlayerLocation(event.getFrom(), player);
data.from = from.getLocation();
if (from.isOnGround())
data.ground = from.getLocation();
final PlayerLocation to = new PlayerLocation(event.getTo(), player);
data.to = to.getLocation();
data.from.set(event.getFrom(), player);
if (data.from.isOnGround())
data.ground = data.from.getLocation();
data.to.set(event.getTo(), player);
Location newTo = null;
if ((player.getGameMode() == GameMode.CREATIVE || player.getAllowFlight()) && creativeFly.isEnabled(player))
// If the player is handled by the creative fly check, execute it.
newTo = creativeFly.check(player, from, to);
newTo = creativeFly.check(player, data.from, data.to);
else if (survivalFly.isEnabled(player)) {
// If he is handled by the survival fly check, execute it.
newTo = survivalFly.check(player, from, to);
newTo = survivalFly.check(player, data.from, data.to);
// If don't have a new location and if he is handled by the no fall check, execute it.
if (newTo == null && noFall.isEnabled(player))
noFall.check(player, from, to);
noFall.check(player, data.from, data.to);
} else
// He isn't handled by any fly check, clear his data.
data.clearFlyData();
if (newTo == null && morePackets.isEnabled(player))
// If he hasn't been stopped by any other check and is handled by the more packets check, execute it.
newTo = morePackets.check(player, from, to);
newTo = morePackets.check(player, data.from, data.to);
else
// Otherwise we need to clear his data.
data.clearMorePacketsData();

View File

@ -262,7 +262,8 @@ public class SurvivalFly extends Check {
else if (wildcard == ParameterName.LOCATION_TO)
return String.format(Locale.US, "%.2f, %.2f, %.2f", data.to.getX(), data.to.getY(), data.to.getZ());
else if (wildcard == ParameterName.DISTANCE)
return String.format(Locale.US, "%.2f", data.to.subtract(data.from).lengthSquared());
return String.format(Locale.US, "%.2f", data.to.getLocation().subtract(data.from.getLocation())
.lengthSquared());
else
return super.getParameter(wildcard, violationData);
}

View File

@ -1,69 +0,0 @@
package fr.neatmonster.nocheatplus.hooks;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import fr.neatmonster.nocheatplus.checks.CheckType;
public class APIUtil {
/**
* Only the children.
*/
private static final Map<CheckType, CheckType[]> childrenMap = new HashMap<CheckType, CheckType[]>();
static{
Map<CheckType, Set<CheckType>> temp = new HashMap<CheckType, Set<CheckType>>();
// uh uh
for (CheckType checkType : CheckType.values()){
Set<CheckType> set = new HashSet<CheckType>();
temp.put(checkType, set);
}
for (CheckType checkType : CheckType.values()){
for (CheckType other : CheckType.values()){
if (isParent(other, checkType)){
temp.get(other).add(checkType);
}
}
}
for (CheckType parent : temp.keySet()){
Set<CheckType> set = temp.get(parent);
CheckType[] a = new CheckType[set.size()];
set.toArray(a);
childrenMap.put(parent, a);
}
}
/**
* Check if propablyParent is ancestor of checkType. Does not check versus checkType directly.
* @param probablyParent
* @param checkType
* @return
*/
public static final boolean isParent(final CheckType probablyParent, final CheckType checkType){
CheckType parent = checkType.getParent();
while (parent != null){
if (parent == probablyParent) return true;
else parent = parent.getParent();
}
return false;
}
/**
* Return an unmodifiable collection of children for the given check type. Always returns a collection, does not contain checkType itself.
* @param checkType
* @return
*/
public static final Collection<CheckType> getChildren(final CheckType checkType){
return Arrays.asList(childrenMap.get(checkType));
}
public static final boolean needsSynchronization(final CheckType checkType){
return checkType == CheckType.CHAT || isParent(CheckType.CHAT, checkType);
}
}

View File

@ -0,0 +1,86 @@
package fr.neatmonster.nocheatplus.hooks;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import fr.neatmonster.nocheatplus.checks.CheckType;
/*
* MMP"""""""MM MM"""""""`YM M""M M""MMMMM""M dP oo dP
* M' .mmmm MM MM mmmmm M M M M MMMMM M 88 88
* M `M M' .M M M M MMMMM M d8888P dP 88 .d8888b.
* M MMMMM MM MM MMMMMMMM M M M MMMMM M 88 88 88 Y8ooooo.
* M MMMMM MM MM MMMMMMMM M M M `MMM' M 88 88 88 88
* M MMMMM MM MM MMMMMMMM M M Mb dM dP dP dP `88888P'
* MMMMMMMMMMMM MMMMMMMMMMMM MMMM MMMMMMMMMMM
*/
/**
* A class providing utilities to the NoCheatPlus API.
*
* @author asofold
*/
public class APIUtils {
/** Only the children. */
private static final Map<CheckType, CheckType[]> childrenMap = new HashMap<CheckType, CheckType[]>();
static {
final Map<CheckType, Set<CheckType>> map = new HashMap<CheckType, Set<CheckType>>();
for (final CheckType type : CheckType.values())
map.put(type, new HashSet<CheckType>());
for (final CheckType type : CheckType.values())
for (final CheckType other : CheckType.values())
if (isParent(other, type))
map.get(other).add(type);
for (final CheckType parent : map.keySet())
childrenMap.put(parent, map.get(parent).toArray(new CheckType[] {}));
}
/**
* Return an unmodifiable collection of children for the given check type. Always returns a collection, does not
* contain check type itself.
*
* @param type
* the check type
* @return the children
*/
public static final Collection<CheckType> getChildren(final CheckType type) {
return Arrays.asList(childrenMap.get(type));
}
/**
* Check if the supposed parent is ancestor of the supposed child. Does not check versus the supposed child
* directly.
*
* @param supposedParent
* the supposed parent
* @param supposedChild
* the supposed child
* @return true, if is parent
*/
public static final boolean isParent(final CheckType supposedParent, final CheckType supposedChild) {
CheckType parent = supposedChild.getParent();
while (parent != null)
if (parent == supposedParent)
return true;
else
parent = parent.getParent();
return false;
}
/**
* Return if the check type requires synchronization.
*
* @param type
* the check type
* @return true, if successful
*/
public static final boolean needsSynchronization(final CheckType type) {
return type == CheckType.CHAT || isParent(CheckType.CHAT, type);
}
}

View File

@ -15,212 +15,244 @@ import org.bukkit.event.player.PlayerQuitEvent;
import fr.neatmonster.nocheatplus.checks.CheckType;
/*
* M"""""""`YM MM'""""'YMM MM"""""""`YM MM""""""""`M dP oo
* M mmmm. M M' .mmm. `M MM mmmmm M MM mmmmmmmM 88
* M MMMMM M M MMMMMooM M' .M M` MMMM dP. .dP .d8888b. 88d8b.d8b. 88d888b. d8888P dP .d8888b. 88d888b.
* M MMMMM M M MMMMMMMM MM MMMMMMMM MM MMMMMMMM `8bd8' 88ooood8 88'`88'`88 88' `88 88 88 88' `88 88' `88
* M MMMMM M M. `MMM' .M MM MMMMMMMM MM MMMMMMMM .d88b. 88. ... 88 88 88 88. .88 88 88 88. .88 88 88
* M MMMMM M MM. .dM MM MMMMMMMM MM .M dP' `dP `88888P' dP dP dP 88Y888P' dP dP `88888P' dP dP
* MMMMMMMMMMM MMMMMMMMMMM MMMMMMMMMMMM MMMMMMMMMMMM 88
* dP
* M"""""`'"""`YM
* M mm. mm. M
* M MMM MMM M .d8888b. 88d888b. .d8888b. .d8888b. .d8888b. 88d888b.
* M MMM MMM M 88' `88 88' `88 88' `88 88' `88 88ooood8 88' `88
* M MMM MMM M 88. .88 88 88 88. .88 88. .88 88. ... 88
* M MMM MMM M `88888P8 dP dP `88888P8 `8888P88 `88888P' dP
* MMMMMMMMMMMMMM .88
* d8888P
*/
/**
* API for exempting players of checks, checked before calculations are done.
*
* @author mc_dev
*
* @author asofold
*/
public class NCPExemptionManager {
/**
* CheckType -> Entity id -> Exemption info.
*
* TODO: opt: move these to checks individually for even faster access.
*/
private static final Map<CheckType, Set<Integer>> exempted = new HashMap<CheckType, Set<Integer>>();
/**
* Registered players (exact name) -> entity id (last time registered).
*/
private static final Map<String, Integer> registeredPlayers = new HashMap<String, Integer>();
static{
clear();
}
/**
* Check if a player is exempted from a check right now.
*
* @param player
* The player to exempt from checks.
* @param checkType
* The type of check to exempt the player from. This can be individual check types, as well as a check group like MOVING or ALL.
* @return
* If the player is exempted from the check right now.
*/
public static final boolean isExempted(final Player player, final CheckType checkType){
return isExempted(player.getEntityId(), checkType);
}
/**
* Check if an entity is exempted from a check by entity id right now.
* <hr>
* This might help exempting NPCs from checks for all time, making performance a lot better. A future purpose might be to exempt vehicles and similar (including passengers) from checks.
* @param id
* Entity id to exempt from checks.
* @param checkType
* The type of check to exempt the player from. This can be individual check types, as well as a check group like MOVING or ALL.
* @return
* If the entity is exempted from checks right now.
*/
public static final boolean isExempted(final int id, final CheckType checkType){
return exempted.get(checkType).contains(id);
}
/**
* Remove all exemptions.
*/
public static final void clear(){
registeredPlayers.clear();
// Use put with a new map to keep entries to stay thread safe.
for (final CheckType checkType : CheckType.values()){
if (APIUtil.needsSynchronization(checkType))
exempted.put(checkType, Collections.synchronizedSet(new HashSet<Integer>(10)));
else
exempted.put(checkType, new HashSet<Integer>(10));
}
}
/**
* This should be registered before all other listeners of NCP (!).
*
* NOTE: For internal use only, DO NOT CALL FROM OUTSIDE.
* @return
*/
public static Listener getListener(){
return new Listener() {
@SuppressWarnings("unused")
@EventHandler(priority=EventPriority.LOWEST)
final void onJoin(final PlayerJoinEvent event){
NCPExemptionManager.registerPlayer(event.getPlayer());
}
@SuppressWarnings("unused")
@EventHandler(priority=EventPriority.MONITOR)
final void onJoin(final PlayerQuitEvent event){
NCPExemptionManager.checkRemovePlayer(event.getPlayer());
}
};
}
/**
* Check if the registeredPlayers mapping can be removed for a player, i.e. no exemptions are present.
* @param player
*/
protected static final void checkRemovePlayer(final Player player) {
if (!registeredPlayers.containsKey(player.getName())) return;
final Integer id = player.getEntityId();
for (final CheckType checkType : CheckType.values()){
// Check if player is exempted from something.
if (isExempted(id, checkType)) return;
}
// No return = remove player.
registeredPlayers.remove(player.getName());
}
/** A map associating a check type with the entity ids of its exempted players. */
private static final Map<CheckType, Set<Integer>> exempted = new HashMap<CheckType, Set<Integer>>();
/** A map associating the registred player with their entity id. */
private static final Map<String, Integer> registeredPlayers = new HashMap<String, Integer>();
static {
clear();
}
/**
* Remove all exemptions.
*/
public static final void clear() {
registeredPlayers.clear();
// Use put with a new map to keep entries to stay thread safe.
for (final CheckType type : CheckType.values())
if (APIUtils.needsSynchronization(type))
exempted.put(type, Collections.synchronizedSet(new HashSet<Integer>()));
else
exempted.put(type, new HashSet<Integer>());
}
/**
* Exempt an entity from all checks permanently.
*
* @param entityId
* the entity id
*/
public static final void exemptPermanently(final int entityId) {
exemptPermanently(entityId, CheckType.ALL);
}
/**
* Exempt an entity from the given check or check group permanently (only until restart).
*
* @param entityId
* the entity id
* @param checkType
* the check type
*/
public static final void exemptPermanently(final int entityId, final CheckType checkType) {
final Integer id = entityId;
exempted.get(checkType).add(id);
for (final CheckType child : APIUtils.getChildren(checkType))
exempted.get(child).add(id);
}
/**
* Exempt a player form all checks permanently.
*
* @param player
* the player
*/
public static final void exemptPermanently(final Player player) {
exemptPermanently(player, CheckType.ALL);
}
/**
* Exempt a player from a check or check group permanently.
*
* @param player
* the player
* @param type
* the check type
*/
public static final void exemptPermanently(final Player player, final CheckType type) {
exemptPermanently(player.getEntityId(), type);
}
/**
* This should be registered before all other listeners of NoCheatPlus.
*
* NOTE: For internal use only, DO NOT CALL FROM OUTSIDE.
*
* @return the listener
*/
public static Listener getListener() {
return new Listener() {
@SuppressWarnings("unused")
@EventHandler(
ignoreCancelled = true, priority = EventPriority.LOWEST)
public void onPlayerJoin(final PlayerJoinEvent event) {
NCPExemptionManager.registerPlayer(event.getPlayer());
}
@SuppressWarnings("unused")
@EventHandler(
ignoreCancelled = true, priority = EventPriority.MONITOR)
public void onPlayerQuit(final PlayerQuitEvent event) {
NCPExemptionManager.tryToRemove(event.getPlayer());
}
};
}
/**
* Check if an entity is exempted from a check right now.
* <hr>
* This might help exempting NPCs from checks for all time, making performance a lot better. A future purpose might
* be to exempt vehicles and similar (including passengers) from checks.
*
* @param entityId
* the entity id to exempt from checks
* @param type
* the type of check to exempt the player from. This can be individual check types, as well as a check
* group like MOVING or ALL
* @return if the entity is exempted from checks right now
*/
public static final boolean isExempted(final int entityId, final CheckType type) {
return exempted.get(type).contains(entityId);
}
/**
* Check if a player is exempted from a check right now.
*
* @param player
* the player to exempt from checks
* @param type
* the type of check to exempt the player from. This can be individual check types, as well as a check
* group like MOVING or ALL
* @return if the player is exempted from the check right now
*/
public static final boolean isExempted(final Player player, final CheckType type) {
return isExempted(player.getEntityId(), type);
}
/**
* Register current entity id for the player.
*
* @param player
* the player
*/
public static final void registerPlayer(final Player player) {
final int entityId = player.getEntityId();
final String name = player.getName();
final Integer registeredId = registeredPlayers.get(name);
if (registeredId == null)
// Player wasn't registered.
registeredPlayers.put(name, entityId);
else if (entityId != registeredId.intValue()) {
// Player was registered under another id (needs exchange).
for (final Set<Integer> set : exempted.values())
if (set.remove(registeredId))
// Replace.
set.add(entityId);
registeredPlayers.put(name, entityId);
}
}
/**
* Check if the registeredPlayers mapping can be removed for a player, i.e. no exemptions are present.
*
* @param player
* the player
*/
protected static final void tryToRemove(final Player player) {
if (!registeredPlayers.containsKey(player.getName()))
return;
final Integer entityId = player.getEntityId();
for (final CheckType type : CheckType.values())
// Check if player is exempted from something.
if (isExempted(entityId, type))
// If he is, we can't remove him so we return.
return;
registeredPlayers.remove(player.getName());
}
/**
* Undo exempting an entity from all checks.
*
* @param entityId
* the entity id
*/
public static final void unexempt(final int entityId) {
unexempt(entityId, CheckType.ALL);
}
/**
* Undo exempting an entity from a certain check, or check group, as given.
*
* @param entityId
* the entity id
* @param type
* the check type
*/
public static final void unexempt(final int entityId, final CheckType type) {
final Integer id = entityId;
exempted.get(type).remove(id);
for (final CheckType child : APIUtils.getChildren(type))
exempted.get(child).remove(id);
}
/**
* Undo exempting a player from all checks.
*
* @param player
* the player
*/
public static final void unexempt(final Player player) {
unexempt(player, CheckType.ALL);
}
/**
* Undo exempting a player form a certain check, or check group, as given.
*
* @param player
* the player
* @param checkType
* the check type
*/
public static final void unexempt(final Player player, final CheckType checkType) {
unexempt(player.getEntityId(), checkType);
}
/**
* Register current entity id for the player.
* @param player
*/
public static final void registerPlayer(final Player player) {
final int newId = player.getEntityId();
final String name = player.getName();
final Integer registeredId = registeredPlayers.get(name);
if (registeredId == null){
// Was not registered.
registeredPlayers.put(name, newId);
}
else if (newId == registeredId.intValue()){
// No change.
}
else {
// Player was registered under another id (needs exchange).
for (final Set<Integer> set : exempted.values()){
if (set.remove(registeredId)){
// replace.
set.add(newId);
}
}
registeredPlayers.put(name, newId);
}
}
/**
* Remove all exempting a player.
* @param player
*/
public static final void unExempt(final Player player){
unExempt(player, CheckType.ALL);
}
/**
* Undo exempting a player form a certain check, or check group, as given.
* @param player
* @param checkType
*/
public static final void unExempt(final Player player, final CheckType checkType){
unExempt(player.getEntityId(), checkType);
}
/**
* Undo exempting an entity by entity id from all checks.
* @param entityId
*/
public static final void unExempt(final int entityId){
unExempt(entityId, CheckType.ALL);
}
/**
* Undo exempting an entity by entity id from a certain check type, also check groups, etc.
* @param entityId
* @param checkType
*/
public static final void unExempt(final int entityId, final CheckType checkType){
final Integer id = entityId;
exempted.get(checkType).remove(id);
for (final CheckType child : APIUtil.getChildren(checkType)){
exempted.get(child).remove(id);
}
}
/**
* Exempt a player form all checks.
* @param player
*/
public static final void exemptPermanently(final Player player){
exemptPermanently(player, CheckType.ALL);
}
/**
* Exempt a player from a check or check group permanently.
* @param player
* @param checkType
*/
public static final void exemptPermanently(final Player player, final CheckType checkType){
exemptPermanently(player.getEntityId(), checkType);
}
/**
* exempt an entity from all checks, by entity id.
* @param entityId
*/
public static final void exemptPermanently(final int entityId){
exemptPermanently(entityId, CheckType.ALL);
}
/**
* Exempt an entity by entity id from the given check or check group permanently (only until restart).
* @param entityId
* @param checkType
*/
public static final void exemptPermanently(final int entityId, final CheckType checkType){
final Integer id = entityId;
exempted.get(checkType).add(id);
for (final CheckType child : APIUtil.getChildren(checkType)){
exempted.get(child).add(id);
}
}
}

View File

@ -36,112 +36,45 @@ import org.bukkit.entity.Player;
*/
public class PlayerLocation {
/**
* Another utility class used to manipulate differently booleans.
*/
private class CustomBoolean {
/** Is the boolean set? */
private boolean isSet = false;
/** What is its value? */
private boolean value = false;
/**
* Gets the boolean.
*
* @return the value
*/
public boolean get() {
return value;
}
/**
* Checks if the boolean is set.
*
* @return true, if the boolean is set
*/
public boolean isSet() {
return isSet;
}
/**
* Sets the boolean.
*
* @param value
* the value
*/
public void set(final boolean value) {
this.value = value;
isSet = true;
}
}
private static final Material[] STAIRS = new Material[] {Material.WOOD_STAIRS, Material.COBBLESTONE_STAIRS,
private static final Material[] STAIRS = new Material[] {Material.WOOD_STAIRS, Material.COBBLESTONE_STAIRS,
Material.BRICK_STAIRS, Material.SMOOTH_STAIRS, Material.NETHER_BRICK_STAIRS, Material.SANDSTONE_STAIRS,
Material.SPRUCE_WOOD_STAIRS, Material.BIRCH_WOOD_STAIRS, Material.JUNGLE_WOOD_STAIRS};
/** The original location. */
private final Location location;
private Location location;
/** Is the player above stairs? */
private final CustomBoolean aboveStairs = new CustomBoolean();
private Boolean aboveStairs;
/** Is the player in lava? */
private final CustomBoolean inLava = new CustomBoolean();
private Boolean inLava;
/** Is the player in water? */
private final CustomBoolean inWater = new CustomBoolean();
private Boolean inWater;
/** Is the player is web? */
private final CustomBoolean inWeb = new CustomBoolean();
private Boolean inWeb;
/** Is the player on the ground? */
private final CustomBoolean onGround = new CustomBoolean();
private Boolean onGround;
/** Is the player on ice? */
private final CustomBoolean onIce = new CustomBoolean();
private Boolean onIce;
/** Is the player on ladder? */
private final CustomBoolean onLadder = new CustomBoolean();
/** Is the player on ladder (ignoring unclimbable vines)? **/
private final CustomBoolean onLadderBis = new CustomBoolean();
/** Is the player on soul sand? */
private final CustomBoolean onSoulSand = new CustomBoolean();
private Boolean onLadder;
/** The bounding box of the player. */
private final AxisAlignedBB boundingBox;
private AxisAlignedBB boundingBox;
/** The entity player. */
private final EntityPlayer entity;
private EntityPlayer entity;
/** The x, y and z coordinates. */
private final int x, y, z;
private int x, y, z;
/** The world. */
private final WorldServer world;
/**
* Instantiates a new player location.
*
* @param location
* the location
* @param player
* the player
*/
public PlayerLocation(final Location location, final Player player) {
this.location = location;
entity = ((CraftPlayer) player).getHandle();
boundingBox = entity.boundingBox.clone().d(location.getX() - entity.locX, location.getY() - entity.locY,
location.getZ() - entity.locZ);
x = (int) Math.floor(location.getX());
y = (int) Math.floor(boundingBox.b);
z = (int) Math.floor(location.getZ());
world = ((CraftWorld) location.getWorld()).getHandle();
}
private WorldServer world;
/**
* Gets the location.
@ -203,9 +136,9 @@ public class PlayerLocation {
* @return true, if the player above on stairs
*/
public boolean isAboveStairs() {
if (!aboveStairs.isSet())
aboveStairs.set(Arrays.asList(STAIRS).contains(Material.getMaterial(world.getTypeId(x, y - 1, z))));
return aboveStairs.get();
if (aboveStairs == null)
aboveStairs = Arrays.asList(STAIRS).contains(Material.getMaterial(world.getTypeId(x, y - 1, z)));
return aboveStairs;
}
/**
@ -214,12 +147,12 @@ public class PlayerLocation {
* @return true, if the player is in lava
*/
public boolean isInLava() {
if (!inLava.isSet()) {
if (inLava == null) {
AxisAlignedBB boundingBoxLava = boundingBox.clone();
boundingBoxLava = boundingBoxLava.grow(-0.10000000149011612D, -0.40000000596046448D, -0.10000000149011612D);
inLava.set(world.a(boundingBoxLava, net.minecraft.server.Material.LAVA));
inLava = world.a(boundingBoxLava, net.minecraft.server.Material.LAVA);
}
return inLava.get();
return inLava;
}
/**
@ -237,13 +170,13 @@ public class PlayerLocation {
* @return true, if the player is in water
*/
public boolean isInWater() {
if (!inWater.isSet()) {
if (inWater == null) {
AxisAlignedBB boundingBoxWater = boundingBox.clone();
boundingBoxWater = boundingBoxWater.grow(0.0D, -0.40000000596046448D, 0.0D);
boundingBoxWater = boundingBoxWater.shrink(0.001D, 0.001D, 0.001D);
inWater.set(world.a(boundingBoxWater, net.minecraft.server.Material.WATER, entity));
inWater = world.a(boundingBoxWater, net.minecraft.server.Material.WATER, entity);
}
return inWater.get();
return inWater;
}
/**
@ -252,19 +185,19 @@ public class PlayerLocation {
* @return true, if the player is in web
*/
public boolean isInWeb() {
if (!inWeb.isSet()) {
if (inWeb == null) {
for (int blockX = (int) Math.floor(boundingBox.a + 0.001D); blockX <= (int) Math
.floor(boundingBox.d - 0.001D); blockX++)
for (int blockY = (int) Math.floor(boundingBox.b + 0.001D); blockY <= (int) Math
.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 (!inWeb.get() && world.getTypeId(blockX, blockY, blockZ) == Block.WEB.id)
inWeb.set(true);
if (!inWeb.isSet())
inWeb.set(false);
if (world.getTypeId(blockX, blockY, blockZ) == Block.WEB.id)
inWeb = true;
if (inWeb == null)
inWeb = false;
}
return inWeb.get();
return inWeb;
}
/**
@ -273,12 +206,12 @@ public class PlayerLocation {
* @return true, if the player is on ground
*/
public boolean isOnGround() {
if (!onGround.isSet()) {
if (onGround == null) {
AxisAlignedBB boundingBoxGround = boundingBox.clone();
boundingBoxGround = boundingBoxGround.d(0D, -0.001D, 0D);
onGround.set(world.getCubes(entity, boundingBoxGround).size() > 0);
onGround = world.getCubes(entity, boundingBoxGround).size() > 0;
}
return onGround.get();
return onGround;
}
/**
@ -287,12 +220,12 @@ public class PlayerLocation {
* @return true, if the player is on ice
*/
public boolean isOnIce() {
if (!onIce.isSet())
if (onIce == null)
if (entity.getBukkitEntity().isSneaking() || entity.getBukkitEntity().isBlocking())
onIce.set(world.getTypeId(x, (int) Math.floor(boundingBox.b - 0.1D), z) == Block.ICE.id);
onIce = world.getTypeId(x, (int) Math.floor(boundingBox.b - 0.1D), z) == Block.ICE.id;
else
onIce.set(world.getTypeId(x, y - 1, z) == Block.ICE.id);
return onIce.get();
onIce = world.getTypeId(x, y - 1, z) == Block.ICE.id;
return onIce;
}
/**
@ -301,71 +234,30 @@ public class PlayerLocation {
* @return true, if the player is on a ladder
*/
public boolean isOnLadder() {
return isOnLadder(false);
if (onLadder == null)
onLadder = world.getTypeId(x, y, z) == Block.LADDER.id || world.getTypeId(x, y, z) == Block.VINE.id;
return onLadder;
}
/**
* Checks if the player is on a ladder.
* Sets the player location object.
*
* @param ignoreUnclimbableVines
* ignore unclimbable vines or not?
* @return true, if the player is on a ladder
* @param location
* the location
* @param player
* the player
*/
public boolean isOnLadder(final boolean ignoreUnclimbableVines) {
if (ignoreUnclimbableVines) {
if (!onLadderBis.isSet())
if (world.getTypeId(x, y, z) == Block.LADDER.id)
onLadderBis.set(true);
else if (world.getTypeId(x, y, z) == Block.VINE.id) {
final int data = world.getData(x, y, z);
if ((data & 1) != 0) {
final int id = world.getTypeId(x, y, z + 1);
if (id != 0 && Block.byId[id].c() && Block.byId[id].material.isSolid())
onLadderBis.set(true);
}
if (!onLadder.isSet() && (data & 2) != 0) {
final int id = world.getTypeId(x - 1, y, z);
if (id != 0 && Block.byId[id].c() && Block.byId[id].material.isSolid())
onLadderBis.set(true);
}
if (!onLadder.isSet() && (data & 4) != 0) {
final int id = world.getTypeId(x, y, z - 1);
if (id != 0 && Block.byId[id].c() && Block.byId[id].material.isSolid())
onLadderBis.set(true);
}
if (!onLadder.isSet() && (data & 8) != 0) {
final int id = world.getTypeId(x + 1, y, z);
if (id != 0 && Block.byId[id].c() && Block.byId[id].material.isSolid())
onLadderBis.set(true);
}
}
return onLadderBis.get();
}
if (!onLadder.isSet())
onLadder.set(world.getTypeId(x, y, z) == Block.LADDER.id || world.getTypeId(x, y, z) == Block.VINE.id);
return onLadder.get();
}
public void set(final Location location, final Player player) {
this.location = location;
/**
* Checks if the player is on soul sand.
*
* @return true, if the player is on soul sand
*/
public boolean isOnSoulSand() {
if (!onSoulSand.isSet()) {
AxisAlignedBB boundingBoxGround = boundingBox.clone();
boundingBoxGround = boundingBoxGround.d(0D, -0.001D, 0D);
for (final Object object : world.getCubes(entity, boundingBoxGround)) {
final AxisAlignedBB aabbCube = (AxisAlignedBB) object;
final int blockX = (int) Math.floor(aabbCube.a);
final int blockY = (int) Math.floor(aabbCube.b);
final int blockZ = (int) Math.floor(aabbCube.c);
if (!onSoulSand.get() && world.getTypeId(blockX, blockY, blockZ) == Block.SOUL_SAND.id)
onSoulSand.set(true);
}
if (!onSoulSand.isSet())
onSoulSand.set(false);
}
return onSoulSand.get();
entity = ((CraftPlayer) player).getHandle();
boundingBox = entity.boundingBox.clone().d(location.getX() - entity.locX, location.getY() - entity.locY,
location.getZ() - entity.locZ);
x = (int) Math.floor(location.getX());
y = (int) Math.floor(boundingBox.b);
z = (int) Math.floor(location.getZ());
world = ((CraftWorld) location.getWorld()).getHandle();
aboveStairs = inLava = inWater = inWeb = onGround = onIce = onLadder = null;
}
}